From 95b0273f27708355d9ad90a5784b349dee7315f6 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Thu, 3 Feb 2022 22:44:16 -0700 Subject: [PATCH 01/37] [async-swiftui-tests] - Had to comment out a bunch to get this compiling, but async await looks like it means we can get rid of that stupid removeQueuedExpectations thing - TT --- .../GenericConstraintTests.swift | 5104 ++++++++--------- .../PersistenceTests.swift | 1088 ++-- .../SwiftCurrent_SwiftUITests/SkipTests.swift | 492 +- .../SwiftCurrent_ModalTests.swift | 844 +-- .../SwiftCurrent_NavigationLinkTests.swift | 814 +-- .../SwiftCurrent_SwiftUITests.swift | 1482 ++--- .../ViewInspector/ViewHostingExtensions.swift | 52 + .../WorkflowItemExtensions.swift | 4 + 8 files changed, 4966 insertions(+), 4914 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 7c459b028..f67948774 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -41,23 +41,22 @@ final class GenericConstraintTests: XCTestCase, View { // MARK: Input Type == Never - func testWhenInputIsNever_WorkflowCanLaunchWithArguments() throws { + func testWhenInputIsNever_WorkflowCanLaunchWithArguments() async throws { struct FR1: View, FlowRepresentable, Inspectable { weak var _workflowPointer: AnyFlowRepresentable? var body: some View { Text(String(describing: Self.self)) } } - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: Optional("Discarded arguments")) { - thenProceed(with: FR1.self) - } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: Optional("Discarded arguments")) { + thenProceed(with: FR1.self) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self)) - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) + XCTAssertNoThrow(try workflowView.find(FR1.self)) } - func testWhenInputIsNeverAndViewDoesNotLoad_WorkflowCanLaunchWithArgumentsAndArgumentsArePassedToTheNextFR() throws { + func testWhenInputIsNeverAndViewDoesNotLoad_WorkflowCanLaunchWithArgumentsAndArgumentsArePassedToTheNextFR() async throws { struct FR1: View, FlowRepresentable, Inspectable { typealias WorkflowOutput = String weak var _workflowPointer: AnyFlowRepresentable? @@ -72,2590 +71,2587 @@ final class GenericConstraintTests: XCTestCase, View { } let expectedArgument = UUID().uuidString - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgument) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR2.self).actualView().input, expectedArgument) - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsNever_FlowPersistenceCanBeSetWithAutoclosure() { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self).persistence(.removedAfterProceeding) - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsNever_PresentationTypeCanBeSetWithAutoclosure() { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self).presentationType(.navigationLink) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().presentationType, .navigationLink) - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsNever_FlowPersistenceCanBeSetWithClosure() { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectation = self.expectation(description: "FlowPersistence closure called") - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self).persistence { - defer { expectation.fulfill() } - return .removedAfterProceeding - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - wait(for: [expectation, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { .removedAfterProceeding } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgument) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() - func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) + XCTAssertEqual(try workflowView.find(FR2.self).actualView().input, expectedArgument) } - func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { + func testWhenInputIsNever_FlowPersistenceCanBeSetWithAutoclosure() async throws { struct FR1: FlowRepresentable, View, Inspectable { var _workflowPointer: AnyFlowRepresentable? var body: some View { Text(String(describing: Self.self)) } } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { .removedAfterProceeding } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self).persistence(.removedAfterProceeding) } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() - func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) } - func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { + func testWhenInputIsNever_PresentationTypeCanBeSetWithAutoclosure() async throws { struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { var _workflowPointer: AnyFlowRepresentable? var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { .removedAfterProceeding } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self).presentationType(.navigationLink) } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - // MARK: Input Type == AnyWorkflow.PassedArgs - - func testWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithAutoclosure() { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self).persistence(.removedAfterProceeding) - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgs_PresentationTypeCanBeSetWithAutoclosure() { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString + }.hostAndInspect(with: \.inspection).extractWorkflowItem() - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self).presentationType(.navigationLink) - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().presentationType, .navigationLink) - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) + XCTAssertEqual(try workflowView.find(FR1.self).actualView().presentationType, .navigationLink) } - func testWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() { + func testWhenInputIsNever_FlowPersistenceCanBeSetWithClosure() async throws { struct FR1: FlowRepresentable, View, Inspectable { var _workflowPointer: AnyFlowRepresentable? var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } } - let expectedArgs = UUID().uuidString - let expectation = self.expectation(description: "FlowPersistence closure called") - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self).persistence { - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) - defer { expectation.fulfill() } - return .removedAfterProceeding - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) - return .removedAfterProceeding - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self).persistence { + defer { expectation.fulfill() } + return .removedAfterProceeding + } } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString + }.hostAndInspect(with: \.inspection).extractWorkflowItem() - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + wait(for: [expectation], timeout: TestConstant.timeout) } - func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { + func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnotherNeverItem() async throws { struct FR1: FlowRepresentable, View, Inspectable { var _workflowPointer: AnyFlowRepresentable? var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } } struct FR2: FlowRepresentable, View, Inspectable { var _workflowPointer: AnyFlowRepresentable? var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) - return .removedAfterProceeding - } } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) - return .removedAfterProceeding - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - // MARK: Input Type == Concrete Type - func testWhenInputIsConcreteType_FlowPersistenceCanBeSetWithAutoclosure() { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self).persistence(.removedAfterProceeding) - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteType_PresentationTypeCanBeSetWithAutoclosure() { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self).presentationType(.navigationLink) - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().presentationType, .navigationLink) - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteType_FlowPersistenceCanBeSetWithClosure() { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let expectation = self.expectation(description: "FlowPersistence closure called") - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self).persistence { - XCTAssertEqual($0, expectedArgs) - defer { expectation.fulfill() } - return .removedAfterProceeding - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { - XCTAssertEqual($0, expectedArgs) - return .removedAfterProceeding - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { - XCTAssertEqual($0, expectedArgs) - return .removedAfterProceeding - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { - XCTAssertEqual($0, expectedArgs) - return .removedAfterProceeding - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence(.removedAfterProceeding) - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { - XCTAssertEqual($0, expectedArgs) - return .removedAfterProceeding - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - // MARK: Generic Proceed Tests - - // MARK: Input Type == Never - - func testProceedingWhenInputIsNever_FlowPersistenceCanBeSetWithAutoclosure() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self).persistence(.removedAfterProceeding) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNever_FlowPersistenceCanBeSetWithClosure() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let expectation = self.expectation(description: "FlowPersistence closure called") - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self).persistence { - defer { expectation.fulfill() } - return .removedAfterProceeding - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - } - wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { .removedAfterProceeding } - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var body: some View { Text(String(describing: Self.self)) } - var _workflowPointer: AnyFlowRepresentable? - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var body: some View { Text(String(describing: Self.self)) } - var _workflowPointer: AnyFlowRepresentable? - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { - XCTAssertEqual($0, 1) - return .removedAfterProceeding - } - } - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - - // MARK: Input Type == AnyWorkflow.PassedArgs - - func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithAutoclosure() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self).persistence(.removedAfterProceeding) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let expectation = self.expectation(description: "FlowPersistence closure called") - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self).persistence { - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) - defer { expectation.fulfill() } - return .removedAfterProceeding - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - } - wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.persistence { - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) - return .removedAfterProceeding - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - try view.actualView().inspect { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) - return .removedAfterProceeding - } - } - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { - XCTAssertEqual($0, 1) - return .removedAfterProceeding - } - } - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - // MARK: Input Type == Concrete Type - func testCreatingMalformedWorkflowWithMismatchingConcreteTypes() throws { - struct FR0: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - - try XCTAssertThrowsFatalError { - _ = WorkflowLauncher(isLaunched: .constant(true)) { - self.thenProceed(with: FR0.self) { - self.thenProceed(with: FR1.self).persistence(.removedAfterProceeding) - } - } - } - } - - func testProceedingWhenInputIsConcreteType_FlowPersistenceCanBeSetWithAutoclosure() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self).persistence(.removedAfterProceeding) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteType_FlowPersistenceCanBeSetWithClosure() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let expectation = self.expectation(description: "FlowPersistence closure called") - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self).persistence { - XCTAssertEqual($0, expectedArgs) - defer { expectation.fulfill() } - return .removedAfterProceeding - } - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) - } - } - wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { .removedAfterProceeding } - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: Int) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { - XCTAssertEqual($0, 1) - return .removedAfterProceeding - } - } - } - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnyWorkflowPassedArgsItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: AnyWorkflow.PassedArgs) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testProceedingTwiceWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnView() { - final class FR0: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - final class FR1: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - final class FR2: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } -} - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -final class ThenProceedOnAppTests: XCTestCase, App { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - - func testThenProceedFunctionsAsExpectedOnApp() { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnApp() { - final class FR0: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - final class FR1: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - final class FR2: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } -} - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -final class ThenProceedOnSceneTests: XCTestCase, Scene { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - - func testThenProceedFunctionsAsExpectedOnScene() { - struct FR0: PassthroughFlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - } - struct FR1: FlowRepresentable, View, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - struct FR2: FlowRepresentable, View, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text(String(describing: Self.self)) } - init(with args: String) { } - } - let expectedArgs = UUID().uuidString - - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).persistence(.removedAfterProceeding) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(FR2.self)) - XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnScene() { - final class FR0: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - final class FR1: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - final class FR2: UIViewController, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - } - - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR0.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) - } - } - } - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.actualView().getWrappedView() + XCTAssertNoThrow(try workflowView.find(type(of: view)).find(FR2.self)) } +// +// func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { .removedAfterProceeding } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { .removedAfterProceeding } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { .removedAfterProceeding } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// // MARK: Input Type == AnyWorkflow.PassedArgs +// +// func testWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithAutoclosure() { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgs_PresentationTypeCanBeSetWithAutoclosure() { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self).presentationType(.navigationLink) +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().presentationType, .navigationLink) +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let expectation = self.expectation(description: "FlowPersistence closure called") +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self).persistence { +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) +// defer { expectation.fulfill() } +// return .removedAfterProceeding +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) +// return .removedAfterProceeding +// } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) +// return .removedAfterProceeding +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) +// return .removedAfterProceeding +// } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// // MARK: Input Type == Concrete Type +// func testWhenInputIsConcreteType_FlowPersistenceCanBeSetWithAutoclosure() { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteType_PresentationTypeCanBeSetWithAutoclosure() { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self).presentationType(.navigationLink) +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().presentationType, .navigationLink) +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteType_FlowPersistenceCanBeSetWithClosure() { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let expectation = self.expectation(description: "FlowPersistence closure called") +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self).persistence { +// XCTAssertEqual($0, expectedArgs) +// defer { expectation.fulfill() } +// return .removedAfterProceeding +// } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { +// XCTAssertEqual($0, expectedArgs) +// return .removedAfterProceeding +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { +// XCTAssertEqual($0, expectedArgs) +// return .removedAfterProceeding +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { +// XCTAssertEqual($0, expectedArgs) +// return .removedAfterProceeding +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence(.removedAfterProceeding) +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { +// XCTAssertEqual($0, expectedArgs) +// return .removedAfterProceeding +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// // MARK: Generic Proceed Tests +// +// // MARK: Input Type == Never +// +// func testProceedingWhenInputIsNever_FlowPersistenceCanBeSetWithAutoclosure() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNever_FlowPersistenceCanBeSetWithClosure() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let expectation = self.expectation(description: "FlowPersistence closure called") +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self).persistence { +// defer { expectation.fulfill() } +// return .removedAfterProceeding +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { .removedAfterProceeding } +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var body: some View { Text(String(describing: Self.self)) } +// var _workflowPointer: AnyFlowRepresentable? +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var body: some View { Text(String(describing: Self.self)) } +// var _workflowPointer: AnyFlowRepresentable? +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { +// XCTAssertEqual($0, 1) +// return .removedAfterProceeding +// } +// } +// } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// +// // MARK: Input Type == AnyWorkflow.PassedArgs +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithAutoclosure() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let expectation = self.expectation(description: "FlowPersistence closure called") +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self).persistence { +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) +// defer { expectation.fulfill() } +// return .removedAfterProceeding +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.persistence { +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) +// return .removedAfterProceeding +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// try view.actualView().inspect { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) +// return .removedAfterProceeding +// } +// } +// } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { +// XCTAssertEqual($0, 1) +// return .removedAfterProceeding +// } +// } +// } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// // MARK: Input Type == Concrete Type +// func testCreatingMalformedWorkflowWithMismatchingConcreteTypes() throws { +// struct FR0: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// +// try XCTAssertThrowsFatalError { +// _ = WorkflowLauncher(isLaunched: .constant(true)) { +// self.thenProceed(with: FR0.self) { +// self.thenProceed(with: FR1.self).persistence(.removedAfterProceeding) +// } +// } +// } +// } +// +// func testProceedingWhenInputIsConcreteType_FlowPersistenceCanBeSetWithAutoclosure() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteType_FlowPersistenceCanBeSetWithClosure() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let expectation = self.expectation(description: "FlowPersistence closure called") +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self).persistence { +// XCTAssertEqual($0, expectedArgs) +// defer { expectation.fulfill() } +// return .removedAfterProceeding +// } +// } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { .removedAfterProceeding } +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: Int) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { +// XCTAssertEqual($0, 1) +// return .removedAfterProceeding +// } +// } +// } +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnyWorkflowPassedArgsItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: AnyWorkflow.PassedArgs) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testProceedingTwiceWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnView() { +// final class FR0: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// final class FR1: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// final class FR2: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +//} +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//final class ThenProceedOnAppTests: XCTestCase, App { +// override func tearDownWithError() throws { +// removeQueuedExpectations() +// } +// +// func testThenProceedFunctionsAsExpectedOnApp() { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnApp() { +// final class FR0: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// final class FR1: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// final class FR2: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +//} +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//final class ThenProceedOnSceneTests: XCTestCase, Scene { +// override func tearDownWithError() throws { +// removeQueuedExpectations() +// } +// +// func testThenProceedFunctionsAsExpectedOnScene() { +// struct FR0: PassthroughFlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// } +// struct FR1: FlowRepresentable, View, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// struct FR2: FlowRepresentable, View, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text(String(describing: Self.self)) } +// init(with args: String) { } +// } +// let expectedArgs = UUID().uuidString +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(FR2.self)) +// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnScene() { +// final class FR0: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// final class FR1: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// final class FR2: UIViewController, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// } +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR0.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } } diff --git a/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift b/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift index 15fe6153c..551aafc00 100644 --- a/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift @@ -1,493 +1,29 @@ +//// +//// PersistenceTests.swift +//// SwiftCurrent_SwiftUI +//// +//// Created by Tyler Thompson on 7/12/21. +//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//// // -// PersistenceTests.swift -// SwiftCurrent_SwiftUI +//import XCTest +//import SwiftUI +//import ViewInspector // -// Created by Tyler Thompson on 7/12/21. -// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//import SwiftCurrent +//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work // - -import XCTest -import SwiftUI -import ViewInspector - -import SwiftCurrent -@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -final class PersistenceTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - - // MARK: RemovedAfterProceedingTests - func testRemovedAfterProceeding_OnFirstItemInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - } - } - .persistence(.removedAfterProceeding) - } - ).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR2.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testRemovedAfterProceeding_OnMiddleItemInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - } - .persistence(.removedAfterProceeding) - } - } - ).inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - } - } - } - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testRemovedAfterProceeding_OnLastItemInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self).persistence(.removedAfterProceeding) - } - } - } - } - .onFinish { _ in expectOnFinish.fulfill() } - ).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - XCTAssertThrowsError(try fr4.find(FR4.self)) - try fr3.actualView().inspect { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self)) - } - } - } - } - } - - wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) - } - - func testRemovedAfterProceeding_OnMultipleItemsInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - .persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - } - ).inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().backUpInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - } - } - } - } - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testRemovedAfterProceeding_OnAllItemsInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let binding = Binding(wrappedValue: true) - let expectOnFinish = expectation(description: "OnFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: binding) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self).persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .onFinish { _ in expectOnFinish.fulfill() }) - .inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - XCTAssertThrowsError(try fr4.find(FR4.self)) - try fr3.actualView().inspect { fr3 in - XCTAssertThrowsError(try fr3.find(FR3.self)) - try fr2.actualView().inspect { fr2 in - XCTAssertThrowsError(try fr2.find(FR2.self)) - try fr1.actualView().inspect { fr1 in - XCTAssertThrowsError(try fr1.find(FR1.self)) - XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") - } - } - } - } - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - // MARK: Closure API Tests - - func testPersistenceWorks_WhenDefinedFromAClosure() throws { - struct FR1: View, FlowRepresentable, Inspectable { - init(with args: String) { } - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let binding = Binding(wrappedValue: true) - let expectOnFinish = expectation(description: "OnFinish called") - let expectedStart = UUID().uuidString - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: binding, startingArgs: expectedStart) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self).persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .persistence { - XCTAssertEqual($0, expectedStart) - return .removedAfterProceeding - } - } - .onFinish { _ in expectOnFinish.fulfill() }) - .inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - XCTAssertThrowsError(try fr4.find(FR4.self)) - try fr3.actualView().inspect { fr3 in - XCTAssertThrowsError(try fr3.find(FR3.self)) - try fr2.actualView().inspect { fr2 in - XCTAssertThrowsError(try fr2.find(FR2.self)) - try fr1.actualView().inspect { fr1 in - XCTAssertThrowsError(try fr1.find(FR1.self)) - XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") - } - } - } - } - } - } - } - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testPersistenceWorks_WhenDefinedFromAClosure_AndItemHasInputOfPassedArgs() throws { - struct FR1: View, FlowRepresentable, Inspectable { - init(with args: AnyWorkflow.PassedArgs) { } - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let binding = Binding(wrappedValue: true) - let expectOnFinish = expectation(description: "OnFinish called") - let expectedStart = AnyWorkflow.PassedArgs.args(UUID().uuidString) - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: binding, startingArgs: expectedStart) { - thenProceed(with: FR1.self) { - - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self).persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .persistence { - XCTAssertNotNil(expectedStart.extractArgs(defaultValue: 1) as? String) - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedStart.extractArgs(defaultValue: 1) as? String) - return .removedAfterProceeding - } - } - .onFinish { _ in expectOnFinish.fulfill() }) - .inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - XCTAssertThrowsError(try fr4.find(FR4.self)) - try fr3.actualView().inspect { fr3 in - XCTAssertThrowsError(try fr3.find(FR3.self)) - try fr2.actualView().inspect { fr2 in - XCTAssertThrowsError(try fr2.find(FR2.self)) - try fr1.actualView().inspect { fr1 in - XCTAssertThrowsError(try fr1.find(FR1.self)) - XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") - } - } - } - } - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testPersistenceWorks_WhenDefinedFromAClosure_AndItemHasInputOfNever() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let binding = Binding(wrappedValue: true) - let expectOnFinish = expectation(description: "OnFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: binding) { - thenProceed(with: FR1.self) { - - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self).persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .persistence(.removedAfterProceeding) - } - .persistence { .removedAfterProceeding } - } - .onFinish { _ in expectOnFinish.fulfill() }) - .inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - XCTAssertThrowsError(try fr4.find(FR4.self)) - try fr3.actualView().inspect { fr3 in - XCTAssertThrowsError(try fr3.find(FR3.self)) - try fr2.actualView().inspect { fr2 in - XCTAssertThrowsError(try fr2.find(FR2.self)) - try fr1.actualView().inspect { fr1 in - XCTAssertThrowsError(try fr1.find(FR1.self)) - XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") - } - } - } - } - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - // MARK: PersistWhenSkippedTests -// func testPersistWhenSkipped_OnFirstItemInAWorkflow() throws { +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//final class PersistenceTests: XCTestCase, View { +// override func tearDownWithError() throws { +// removeQueuedExpectations() +// } +// +// // MARK: RemovedAfterProceedingTests +// func testRemovedAfterProceeding_OnFirstItemInAWorkflow() throws { // struct FR1: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR1 type") } -// func shouldLoad() -> Bool { false } // } // struct FR2: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? @@ -510,21 +46,17 @@ final class PersistenceTests: XCTestCase, View { // } // } // } -// .persistence(.persistWhenSkipped) +// .persistence(.removedAfterProceeding) // } -// ).inspection.inspect { fr1 in -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().backUpInWorkflow()) -// try fr1.actualView().inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// ).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR2.self).actualView().backUpInWorkflow()) +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) // try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) -// } -// } +// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) // } // } // } @@ -532,8 +64,8 @@ final class PersistenceTests: XCTestCase, View { // // wait(for: [expectViewLoaded], timeout: TestConstant.timeout) // } -// -// func testPersistWhenSkipped_OnMiddleItemInAWorkflow() throws { +// +// func testRemovedAfterProceeding_OnMiddleItemInAWorkflow() throws { // struct FR1: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR1 type") } @@ -541,7 +73,6 @@ final class PersistenceTests: XCTestCase, View { // struct FR2: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } // } // struct FR3: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? @@ -559,21 +90,24 @@ final class PersistenceTests: XCTestCase, View { // thenProceed(with: FR4.self) // } // } -// .persistence(.persistWhenSkipped) +// .persistence(.removedAfterProceeding) // } // } // ).inspection.inspect { fr1 in // XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) // try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertThrowsError(try fr2.find(FR2.self)) +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) // try fr2.actualView().inspectWrapped { fr3 in // XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) -// try fr2.actualView().inspect { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// } // } // } // } @@ -583,8 +117,8 @@ final class PersistenceTests: XCTestCase, View { // // wait(for: [expectViewLoaded], timeout: TestConstant.timeout) // } -// -// func testPersistWhenSkipped_OnLastItemInAWorkflow() throws { +// +// func testRemovedAfterProceeding_OnLastItemInAWorkflow() throws { // struct FR1: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR1 type") } @@ -600,7 +134,6 @@ final class PersistenceTests: XCTestCase, View { // struct FR4: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR4 type") } -// func shouldLoad() -> Bool { false } // } // let expectOnFinish = expectation(description: "OnFinish called") // let expectViewLoaded = ViewHosting.loadView( @@ -608,26 +141,33 @@ final class PersistenceTests: XCTestCase, View { // thenProceed(with: FR1.self) { // thenProceed(with: FR2.self) { // thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self).persistence(.persistWhenSkipped) +// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) // } // } // } // } -// .onFinish { _ in expectOnFinish.fulfill() }) -// .inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +// .onFinish { _ in expectOnFinish.fulfill() } +// ).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// XCTAssertThrowsError(try fr4.find(FR4.self)) +// try fr3.actualView().inspect { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self)) +// } // } // } // } +// } // // wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) // } // -// func testPersistWhenSkipped_OnMultipleItemsInAWorkflow() throws { +// func testRemovedAfterProceeding_OnMultipleItemsInAWorkflow() throws { // struct FR1: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR1 type") } @@ -635,12 +175,10 @@ final class PersistenceTests: XCTestCase, View { // struct FR2: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } // } // struct FR3: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR3 type") } -// func shouldLoad() -> Bool { false } // } // struct FR4: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? @@ -653,25 +191,25 @@ final class PersistenceTests: XCTestCase, View { // thenProceed(with: FR3.self) { // thenProceed(with: FR4.self) // } -// .persistence(.persistWhenSkipped) +// .persistence(.removedAfterProceeding) // } -// .persistence(.persistWhenSkipped) +// .persistence(.removedAfterProceeding) // } // } // ).inspection.inspect { fr1 in // XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) // try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertThrowsError(try fr2.find(FR2.self)) +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) // try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertThrowsError(try fr3.find(FR3.self)) +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) // try fr3.actualView().inspectWrapped { fr4 in // XCTAssertNoThrow(try fr4.find(FR4.self).actualView().backUpInWorkflow()) -// try fr3.actualView().inspect { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) -// try fr2.actualView().inspect { fr2 in +// try fr1.actualView().inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in // XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) // try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertThrowsError(try fr3.find(FR3.self)) +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) // try fr3.actualView().inspectWrapped { fr4 in // XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) // } @@ -682,56 +220,518 @@ final class PersistenceTests: XCTestCase, View { // } // } // } +// // wait(for: [expectViewLoaded], timeout: TestConstant.timeout) // } // -// func testPersistWhenSkipped_OnAllItemsInAWorkflow() throws { +// func testRemovedAfterProceeding_OnAllItemsInAWorkflow() throws { // struct FR1: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR1 type") } -// func shouldLoad() -> Bool { false } // } // struct FR2: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } // } // struct FR3: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR3 type") } -// func shouldLoad() -> Bool { false } // } // struct FR4: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? // var body: some View { Text("FR4 type") } -// func shouldLoad() -> Bool { false } // } +// let binding = Binding(wrappedValue: true) // let expectOnFinish = expectation(description: "OnFinish called") // let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { +// WorkflowLauncher(isLaunched: binding) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) +// } +// .persistence(.removedAfterProceeding) +// } +// .persistence(.removedAfterProceeding) +// } +// .persistence(.removedAfterProceeding) +// } +// .onFinish { _ in expectOnFinish.fulfill() }) +// .inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// XCTAssertThrowsError(try fr4.find(FR4.self)) +// try fr3.actualView().inspect { fr3 in +// XCTAssertThrowsError(try fr3.find(FR3.self)) +// try fr2.actualView().inspect { fr2 in +// XCTAssertThrowsError(try fr2.find(FR2.self)) +// try fr1.actualView().inspect { fr1 in +// XCTAssertThrowsError(try fr1.find(FR1.self)) +// XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") +// } +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// // MARK: Closure API Tests +// +// func testPersistenceWorks_WhenDefinedFromAClosure() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// init(with args: String) { } +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let binding = Binding(wrappedValue: true) +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectedStart = UUID().uuidString +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: binding, startingArgs: expectedStart) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) +// } +// .persistence(.removedAfterProceeding) +// } +// .persistence(.removedAfterProceeding) +// } +// .persistence { +// XCTAssertEqual($0, expectedStart) +// return .removedAfterProceeding +// } +// } +// .onFinish { _ in expectOnFinish.fulfill() }) +// .inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// XCTAssertThrowsError(try fr4.find(FR4.self)) +// try fr3.actualView().inspect { fr3 in +// XCTAssertThrowsError(try fr3.find(FR3.self)) +// try fr2.actualView().inspect { fr2 in +// XCTAssertThrowsError(try fr2.find(FR2.self)) +// try fr1.actualView().inspect { fr1 in +// XCTAssertThrowsError(try fr1.find(FR1.self)) +// XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") +// } +// } +// } +// } +// } +// } +// } +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testPersistenceWorks_WhenDefinedFromAClosure_AndItemHasInputOfPassedArgs() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// init(with args: AnyWorkflow.PassedArgs) { } +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let binding = Binding(wrappedValue: true) +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectedStart = AnyWorkflow.PassedArgs.args(UUID().uuidString) +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: binding, startingArgs: expectedStart) { +// thenProceed(with: FR1.self) { +// +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) +// } +// .persistence(.removedAfterProceeding) +// } +// .persistence(.removedAfterProceeding) +// } +// .persistence { +// XCTAssertNotNil(expectedStart.extractArgs(defaultValue: 1) as? String) +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedStart.extractArgs(defaultValue: 1) as? String) +// return .removedAfterProceeding +// } +// } +// .onFinish { _ in expectOnFinish.fulfill() }) +// .inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// XCTAssertThrowsError(try fr4.find(FR4.self)) +// try fr3.actualView().inspect { fr3 in +// XCTAssertThrowsError(try fr3.find(FR3.self)) +// try fr2.actualView().inspect { fr2 in +// XCTAssertThrowsError(try fr2.find(FR2.self)) +// try fr1.actualView().inspect { fr1 in +// XCTAssertThrowsError(try fr1.find(FR1.self)) +// XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") +// } +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testPersistenceWorks_WhenDefinedFromAClosure_AndItemHasInputOfNever() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let binding = Binding(wrappedValue: true) +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: binding) { // thenProceed(with: FR1.self) { +// // thenProceed(with: FR2.self) { // thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self).persistence(.persistWhenSkipped) +// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) // } -// .persistence(.persistWhenSkipped) +// .persistence(.removedAfterProceeding) // } -// .persistence(.persistWhenSkipped) +// .persistence(.removedAfterProceeding) // } -// .persistence(.persistWhenSkipped) +// .persistence { .removedAfterProceeding } // } // .onFinish { _ in expectOnFinish.fulfill() }) // .inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) // try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertThrowsError(try fr2.find(FR2.self)) +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) // try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertThrowsError(try fr3.find(FR3.self)) +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) // try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertNoThrow(try fr4.find(FR4.self)) +// XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// XCTAssertThrowsError(try fr4.find(FR4.self)) +// try fr3.actualView().inspect { fr3 in +// XCTAssertThrowsError(try fr3.find(FR3.self)) +// try fr2.actualView().inspect { fr2 in +// XCTAssertThrowsError(try fr2.find(FR2.self)) +// try fr1.actualView().inspect { fr1 in +// XCTAssertThrowsError(try fr1.find(FR1.self)) +// XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") +// } +// } +// } // } // } // } // } +// // wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) // } -} +// +// // MARK: PersistWhenSkippedTests +//// func testPersistWhenSkipped_OnFirstItemInAWorkflow() throws { +//// struct FR1: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR1 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// struct FR2: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR2 type") } +//// } +//// struct FR3: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR3 type") } +//// } +//// struct FR4: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR4 type") } +//// } +//// let expectViewLoaded = ViewHosting.loadView( +//// WorkflowLauncher(isLaunched: .constant(true)) { +//// thenProceed(with: FR1.self) { +//// thenProceed(with: FR2.self) { +//// thenProceed(with: FR3.self) { +//// thenProceed(with: FR4.self) +//// } +//// } +//// } +//// .persistence(.persistWhenSkipped) +//// } +//// ).inspection.inspect { fr1 in +//// try fr1.actualView().inspectWrapped { fr2 in +//// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().backUpInWorkflow()) +//// try fr1.actualView().inspect { viewUnderTest in +//// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +//// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +//// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +//// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) +//// } +//// } +//// } +//// } +//// } +//// } +//// +//// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +//// } +//// +//// func testPersistWhenSkipped_OnMiddleItemInAWorkflow() throws { +//// struct FR1: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR1 type") } +//// } +//// struct FR2: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR2 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// struct FR3: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR3 type") } +//// } +//// struct FR4: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR4 type") } +//// } +//// let expectViewLoaded = ViewHosting.loadView( +//// WorkflowLauncher(isLaunched: .constant(true)) { +//// thenProceed(with: FR1.self) { +//// thenProceed(with: FR2.self) { +//// thenProceed(with: FR3.self) { +//// thenProceed(with: FR4.self) +//// } +//// } +//// .persistence(.persistWhenSkipped) +//// } +//// } +//// ).inspection.inspect { fr1 in +//// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +//// try fr1.actualView().inspectWrapped { fr2 in +//// XCTAssertThrowsError(try fr2.find(FR2.self)) +//// try fr2.actualView().inspectWrapped { fr3 in +//// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) +//// try fr2.actualView().inspect { fr2 in +//// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +//// try fr2.actualView().inspectWrapped { fr3 in +//// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +//// try fr3.actualView().inspectWrapped { fr4 in +//// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +//// } +//// } +//// } +//// } +//// } +//// } +//// +//// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +//// } +//// +//// func testPersistWhenSkipped_OnLastItemInAWorkflow() throws { +//// struct FR1: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR1 type") } +//// } +//// struct FR2: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR2 type") } +//// } +//// struct FR3: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR3 type") } +//// } +//// struct FR4: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR4 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// let expectOnFinish = expectation(description: "OnFinish called") +//// let expectViewLoaded = ViewHosting.loadView( +//// WorkflowLauncher(isLaunched: .constant(true)) { +//// thenProceed(with: FR1.self) { +//// thenProceed(with: FR2.self) { +//// thenProceed(with: FR3.self) { +//// thenProceed(with: FR4.self).persistence(.persistWhenSkipped) +//// } +//// } +//// } +//// } +//// .onFinish { _ in expectOnFinish.fulfill() }) +//// .inspection.inspect { viewUnderTest in +//// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +//// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +//// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +//// } +//// } +//// } +//// +//// wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) +//// } +//// +//// func testPersistWhenSkipped_OnMultipleItemsInAWorkflow() throws { +//// struct FR1: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR1 type") } +//// } +//// struct FR2: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR2 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// struct FR3: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR3 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// struct FR4: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR4 type") } +//// } +//// let expectViewLoaded = ViewHosting.loadView( +//// WorkflowLauncher(isLaunched: .constant(true)) { +//// thenProceed(with: FR1.self) { +//// thenProceed(with: FR2.self) { +//// thenProceed(with: FR3.self) { +//// thenProceed(with: FR4.self) +//// } +//// .persistence(.persistWhenSkipped) +//// } +//// .persistence(.persistWhenSkipped) +//// } +//// } +//// ).inspection.inspect { fr1 in +//// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +//// try fr1.actualView().inspectWrapped { fr2 in +//// XCTAssertThrowsError(try fr2.find(FR2.self)) +//// try fr2.actualView().inspectWrapped { fr3 in +//// XCTAssertThrowsError(try fr3.find(FR3.self)) +//// try fr3.actualView().inspectWrapped { fr4 in +//// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().backUpInWorkflow()) +//// try fr3.actualView().inspect { fr3 in +//// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) +//// try fr2.actualView().inspect { fr2 in +//// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +//// try fr2.actualView().inspectWrapped { fr3 in +//// XCTAssertThrowsError(try fr3.find(FR3.self)) +//// try fr3.actualView().inspectWrapped { fr4 in +//// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +//// } +//// } +//// } +//// } +//// } +//// } +//// } +//// } +//// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +//// } +//// +//// func testPersistWhenSkipped_OnAllItemsInAWorkflow() throws { +//// struct FR1: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR1 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// struct FR2: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR2 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// struct FR3: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR3 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// struct FR4: View, FlowRepresentable, Inspectable { +//// var _workflowPointer: AnyFlowRepresentable? +//// var body: some View { Text("FR4 type") } +//// func shouldLoad() -> Bool { false } +//// } +//// let expectOnFinish = expectation(description: "OnFinish called") +//// let expectViewLoaded = ViewHosting.loadView( +//// WorkflowLauncher(isLaunched: .constant(true)) { +//// thenProceed(with: FR1.self) { +//// thenProceed(with: FR2.self) { +//// thenProceed(with: FR3.self) { +//// thenProceed(with: FR4.self).persistence(.persistWhenSkipped) +//// } +//// .persistence(.persistWhenSkipped) +//// } +//// .persistence(.persistWhenSkipped) +//// } +//// .persistence(.persistWhenSkipped) +//// } +//// .onFinish { _ in expectOnFinish.fulfill() }) +//// .inspection.inspect { fr1 in +//// try fr1.actualView().inspectWrapped { fr2 in +//// XCTAssertThrowsError(try fr2.find(FR2.self)) +//// try fr2.actualView().inspectWrapped { fr3 in +//// XCTAssertThrowsError(try fr3.find(FR3.self)) +//// try fr3.actualView().inspectWrapped { fr4 in +//// XCTAssertNoThrow(try fr4.find(FR4.self)) +//// } +//// } +//// } +//// } +//// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +//// } +//} diff --git a/Tests/SwiftCurrent_SwiftUITests/SkipTests.swift b/Tests/SwiftCurrent_SwiftUITests/SkipTests.swift index 5a966e494..105137664 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SkipTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SkipTests.swift @@ -1,249 +1,249 @@ +//// +//// SkipTests.swift +//// SwiftCurrent +//// +//// Created by Tyler Thompson on 7/12/21. +//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//// // -// SkipTests.swift -// SwiftCurrent +//import XCTest +//import SwiftUI +//import ViewInspector // -// Created by Tyler Thompson on 7/12/21. -// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//import SwiftCurrent +//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work // - -import XCTest -import SwiftUI -import ViewInspector - -import SwiftCurrent -@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -final class SkipTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - - func testSkippingFirstItemInAWorkflow() throws { - // NOTE: Workflows in the past had issues with 4+ items, so this is to cover our bases. SwiftUI also has a nasty habit of behaving a little differently as number of views increase. - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - func shouldLoad() -> Bool { false } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - } - } - } - ).inspection.inspect { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testSkippingMiddleItemInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - func shouldLoad() -> Bool { false } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - } - } - } - ).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testSkippingLastItemInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - func shouldLoad() -> Bool { false } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - } - } - } - .onFinish { _ in expectOnFinish.fulfill() }) - .inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - XCTAssertThrowsError(try fr3.find(FR4.self)) - XCTAssertNoThrow(try fr3.find(FR3.self)) - } - } - } - - wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) - } - - func testSkippingMultipleItemsInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - func shouldLoad() -> Bool { false } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - func shouldLoad() -> Bool { false } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - } - } - } - ).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR2.self).actualView()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR3.self).actualView()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testSkippingAllItemsInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - func shouldLoad() -> Bool { false } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - func shouldLoad() -> Bool { false } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - func shouldLoad() -> Bool { false } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - func shouldLoad() -> Bool { false } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - } - } - } - .onFinish { _ in expectOnFinish.fulfill() }) - .inspection.inspect { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR3.self)) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertThrowsError(try viewUnderTest.find(FR4.self)) - } - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } -} +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//final class SkipTests: XCTestCase, View { +// override func tearDownWithError() throws { +// removeQueuedExpectations() +// } +// +// func testSkippingFirstItemInAWorkflow() throws { +// // NOTE: Workflows in the past had issues with 4+ items, so this is to cover our bases. SwiftUI also has a nasty habit of behaving a little differently as number of views increase. +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// } +// } +// } +// ).inspection.inspect { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testSkippingMiddleItemInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// } +// } +// } +// ).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testSkippingLastItemInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// func shouldLoad() -> Bool { false } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// } +// } +// } +// .onFinish { _ in expectOnFinish.fulfill() }) +// .inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// XCTAssertThrowsError(try fr3.find(FR4.self)) +// XCTAssertNoThrow(try fr3.find(FR3.self)) +// } +// } +// } +// +// wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) +// } +// +// func testSkippingMultipleItemsInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// } +// } +// } +// ).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR2.self).actualView()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR3.self).actualView()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testSkippingAllItemsInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// func shouldLoad() -> Bool { false } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// } +// } +// } +// .onFinish { _ in expectOnFinish.fulfill() }) +// .inspection.inspect { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR3.self)) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertThrowsError(try viewUnderTest.find(FR4.self)) +// } +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +//} diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift index d3db1b4d7..73097c849 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift @@ -1,423 +1,423 @@ +//// +//// SwiftCurrent_ModalTests.swift +//// SwiftCurrent +//// +//// Created by Tyler Thompson on 7/12/21. +//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//// // -// SwiftCurrent_ModalTests.swift -// SwiftCurrent -// -// Created by Tyler Thompson on 7/12/21. -// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -// - -import XCTest -import SwiftUI - -import SwiftCurrent - -@testable import ViewInspector -@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -extension InspectableView where View == ViewType.Sheet { - func isPresented() throws -> Bool { - return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false - } -} - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -final class SwiftCurrent_ModalTests: XCTestCase, Scene { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - - func testWorkflowCanBeFollowed() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).presentationType(.modal) - } - } - .onFinish { _ in - expectOnFinish.fulfill() - }).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertEqual(try fr1.find(FR1.self).text().string(), "FR1 type") - try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in - XCTAssertTrue(try fr1.find(ViewType.Sheet.self).isPresented()) - try fr1.find(ViewType.Sheet.self).find(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr2 in - XCTAssertEqual(try fr2.view(FR2.self).text().string(), "FR2 type") - XCTAssertNoThrow(try fr2.view(FR2.self).actualView().proceedInWorkflow()) - } - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowItemsOfTheSameTypeCanBeFollowed() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR1.self).presentationType(.modal) - }.presentationType(.modal) - } - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { first in - XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) - try first.find(ViewType.Sheet.self).view(WorkflowItem, FR1>.self).actualView().inspect(model: model, launcher: launcher) { second in - XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) - XCTAssertNoThrow(try second.find(FR1.self).actualView().proceedInWorkflow()) - try second.actualView().inspect { second in - XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) - try second.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { third in - XCTAssertNoThrow(try third.find(FR1.self).actualView().proceedInWorkflow()) - try third.actualView().inspect { third in - XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) - } - } - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testLargeWorkflowCanBeFollowed() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - struct FR5: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR5 type") } - } - struct FR6: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR6 type") } - } - struct FR7: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR7 type") } - } - var model: WorkflowViewModel! - var launcher: Launcher! - var fr1: InspectableView, FR6>, FR5>, FR4>, FR3>, FR2>, FR1>>>! - var fr2: InspectableView, FR6>, FR5>, FR4>, FR3>, FR2>>>! - var fr3: InspectableView, FR6>, FR5>, FR4>, FR3>>>! - var fr4: InspectableView, FR6>, FR5>, FR4>>>! - var fr5: InspectableView, FR6>, FR5>>>! - var fr6: InspectableView, FR6>>>! - - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) { - thenProceed(with: FR5.self) { - thenProceed(with: FR6.self) { - thenProceed(with: FR7.self).presentationType(.modal) - }.presentationType(.modal) - }.presentationType(.modal) - }.presentationType(.modal) - }.presentationType(.modal) - }.presentationType(.modal) - } - } - ).inspection.inspect { fr_1 in - model = (Mirror(reflecting: try fr_1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - launcher = (Mirror(reflecting: try fr_1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertNoThrow(try fr_1.find(FR1.self).actualView().proceedInWorkflow()) - try fr_1.actualView().inspect { fr_1 in - XCTAssert(try fr_1.find(ViewType.Sheet.self).isPresented()) - fr1 = fr_1 - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - - removeQueuedExpectations() - - try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr_2 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssertNoThrow(try fr_2.find(FR2.self).actualView().proceedInWorkflow()) - try fr_2.actualView().inspect { fr_2 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr_2.find(ViewType.Sheet.self).isPresented()) - fr2 = fr_2 - } - } - - removeQueuedExpectations() - - try fr2.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>.self).actualView().inspect(model: model, launcher: launcher) { fr_3 in - XCTAssertNoThrow(try fr_3.find(FR3.self).actualView().proceedInWorkflow()) - try fr_3.actualView().inspect { fr_3 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr_3.find(ViewType.Sheet.self).isPresented()) - fr3 = fr_3 - } - } - - removeQueuedExpectations() - - try fr3.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>.self).actualView().inspect(model: model, launcher: launcher) { fr_4 in - XCTAssertNoThrow(try fr_4.find(FR4.self).actualView().proceedInWorkflow()) - try fr_4.actualView().inspect { fr_4 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr_4.find(ViewType.Sheet.self).isPresented()) - fr4 = fr_4 - } - } - - removeQueuedExpectations() - - try fr4.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>.self).actualView().inspect(model: model, launcher: launcher) { fr_5 in - XCTAssertNoThrow(try fr_5.find(FR5.self).actualView().proceedInWorkflow()) - try fr_5.actualView().inspect { fr_5 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr_5.find(ViewType.Sheet.self).isPresented()) - fr5 = fr_5 - } - } - - removeQueuedExpectations() - - try fr5.find(ViewType.Sheet.self).view(WorkflowItem, FR6>.self).actualView().inspect(model: model, launcher: launcher) { fr_6 in - XCTAssertNoThrow(try fr_6.find(FR6.self).actualView().proceedInWorkflow()) - try fr_6.actualView().inspect { fr_6 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr5.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr_6.find(ViewType.Sheet.self).isPresented()) - fr6 = fr_6 - } - } - - removeQueuedExpectations() - - try fr6.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr7 in - XCTAssertNoThrow(try fr7.find(FR7.self).actualView().proceedInWorkflow()) - try fr7.actualView().inspect { fr7 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr5.find(ViewType.Sheet.self).isPresented()) - XCTAssert(try fr6.find(ViewType.Sheet.self).isPresented()) - } - } - } - - func testNavLinkWorkflowsCanSkipTheFirstItem() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - func shouldLoad() -> Bool { false } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self).presentationType(.modal) - }.presentationType(.modal) - } - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertThrowsError(try fr1.find(FR1.self).actualView()) - try fr1.view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspect { fr2 in - try fr2.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in - XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) - XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testNavLinkWorkflowsCanSkipOneItemInTheMiddle() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - func shouldLoad() -> Bool { false } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self).presentationType(.modal) - }.presentationType(.modal) - } - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) - XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testNavLinkWorkflowsCanSkipTwoItemsInTheMiddle() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - func shouldLoad() -> Bool { false } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - func shouldLoad() -> Bool { false } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self).presentationType(.modal) - } - }.presentationType(.modal) - } - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR3>, FR2>.self).view(WorkflowItem, FR3>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr4 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) - XCTAssertThrowsError(try fr1.find(FR3.self).actualView()) - XCTAssertNoThrow(try fr4.find(FR4.self).actualView()) - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testNavLinkWorkflowsCanSkipLastItem() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - func shouldLoad() -> Bool { false } - } - - let expectOnFinish = expectation(description: "onFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self).presentationType(.modal) - }.presentationType(.modal) - } - } - .onFinish { _ in - expectOnFinish.fulfill() - }).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in - XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - -} +//import XCTest +//import SwiftUI +// +//import SwiftCurrent +// +//@testable import ViewInspector +//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//extension InspectableView where View == ViewType.Sheet { +// func isPresented() throws -> Bool { +// return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false +// } +//} +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//final class SwiftCurrent_ModalTests: XCTestCase, Scene { +// override func tearDownWithError() throws { +// removeQueuedExpectations() +// } +// +// func testWorkflowCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).presentationType(.modal) +// } +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertEqual(try fr1.find(FR1.self).text().string(), "FR1 type") +// try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in +// XCTAssertTrue(try fr1.find(ViewType.Sheet.self).isPresented()) +// try fr1.find(ViewType.Sheet.self).find(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr2 in +// XCTAssertEqual(try fr2.view(FR2.self).text().string(), "FR2 type") +// XCTAssertNoThrow(try fr2.view(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowItemsOfTheSameTypeCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR1.self).presentationType(.modal) +// }.presentationType(.modal) +// } +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { first in +// XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) +// try first.find(ViewType.Sheet.self).view(WorkflowItem, FR1>.self).actualView().inspect(model: model, launcher: launcher) { second in +// XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) +// XCTAssertNoThrow(try second.find(FR1.self).actualView().proceedInWorkflow()) +// try second.actualView().inspect { second in +// XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) +// try second.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { third in +// XCTAssertNoThrow(try third.find(FR1.self).actualView().proceedInWorkflow()) +// try third.actualView().inspect { third in +// XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testLargeWorkflowCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// struct FR5: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR5 type") } +// } +// struct FR6: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR6 type") } +// } +// struct FR7: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR7 type") } +// } +// var model: WorkflowViewModel! +// var launcher: Launcher! +// var fr1: InspectableView, FR6>, FR5>, FR4>, FR3>, FR2>, FR1>>>! +// var fr2: InspectableView, FR6>, FR5>, FR4>, FR3>, FR2>>>! +// var fr3: InspectableView, FR6>, FR5>, FR4>, FR3>>>! +// var fr4: InspectableView, FR6>, FR5>, FR4>>>! +// var fr5: InspectableView, FR6>, FR5>>>! +// var fr6: InspectableView, FR6>>>! +// +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) { +// thenProceed(with: FR5.self) { +// thenProceed(with: FR6.self) { +// thenProceed(with: FR7.self).presentationType(.modal) +// }.presentationType(.modal) +// }.presentationType(.modal) +// }.presentationType(.modal) +// }.presentationType(.modal) +// }.presentationType(.modal) +// } +// } +// ).inspection.inspect { fr_1 in +// model = (Mirror(reflecting: try fr_1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// launcher = (Mirror(reflecting: try fr_1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertNoThrow(try fr_1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr_1.actualView().inspect { fr_1 in +// XCTAssert(try fr_1.find(ViewType.Sheet.self).isPresented()) +// fr1 = fr_1 +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// +// removeQueuedExpectations() +// +// try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr_2 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssertNoThrow(try fr_2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr_2.actualView().inspect { fr_2 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr_2.find(ViewType.Sheet.self).isPresented()) +// fr2 = fr_2 +// } +// } +// +// removeQueuedExpectations() +// +// try fr2.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>.self).actualView().inspect(model: model, launcher: launcher) { fr_3 in +// XCTAssertNoThrow(try fr_3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr_3.actualView().inspect { fr_3 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr_3.find(ViewType.Sheet.self).isPresented()) +// fr3 = fr_3 +// } +// } +// +// removeQueuedExpectations() +// +// try fr3.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>.self).actualView().inspect(model: model, launcher: launcher) { fr_4 in +// XCTAssertNoThrow(try fr_4.find(FR4.self).actualView().proceedInWorkflow()) +// try fr_4.actualView().inspect { fr_4 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr_4.find(ViewType.Sheet.self).isPresented()) +// fr4 = fr_4 +// } +// } +// +// removeQueuedExpectations() +// +// try fr4.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>.self).actualView().inspect(model: model, launcher: launcher) { fr_5 in +// XCTAssertNoThrow(try fr_5.find(FR5.self).actualView().proceedInWorkflow()) +// try fr_5.actualView().inspect { fr_5 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr_5.find(ViewType.Sheet.self).isPresented()) +// fr5 = fr_5 +// } +// } +// +// removeQueuedExpectations() +// +// try fr5.find(ViewType.Sheet.self).view(WorkflowItem, FR6>.self).actualView().inspect(model: model, launcher: launcher) { fr_6 in +// XCTAssertNoThrow(try fr_6.find(FR6.self).actualView().proceedInWorkflow()) +// try fr_6.actualView().inspect { fr_6 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr5.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr_6.find(ViewType.Sheet.self).isPresented()) +// fr6 = fr_6 +// } +// } +// +// removeQueuedExpectations() +// +// try fr6.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr7 in +// XCTAssertNoThrow(try fr7.find(FR7.self).actualView().proceedInWorkflow()) +// try fr7.actualView().inspect { fr7 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr5.find(ViewType.Sheet.self).isPresented()) +// XCTAssert(try fr6.find(ViewType.Sheet.self).isPresented()) +// } +// } +// } +// +// func testNavLinkWorkflowsCanSkipTheFirstItem() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self).presentationType(.modal) +// }.presentationType(.modal) +// } +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertThrowsError(try fr1.find(FR1.self).actualView()) +// try fr1.view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspect { fr2 in +// try fr2.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in +// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testNavLinkWorkflowsCanSkipOneItemInTheMiddle() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self).presentationType(.modal) +// }.presentationType(.modal) +// } +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testNavLinkWorkflowsCanSkipTwoItemsInTheMiddle() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self).presentationType(.modal) +// } +// }.presentationType(.modal) +// } +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR3>, FR2>.self).view(WorkflowItem, FR3>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr4 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) +// XCTAssertThrowsError(try fr1.find(FR3.self).actualView()) +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView()) +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testNavLinkWorkflowsCanSkipLastItem() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// func shouldLoad() -> Bool { false } +// } +// +// let expectOnFinish = expectation(description: "onFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self).presentationType(.modal) +// }.presentationType(.modal) +// } +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in +// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +//} diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift index a410940cf..9bceebcb4 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift @@ -1,410 +1,410 @@ +//// +//// SwiftCurrent_NavigationLinkTests.swift +//// SwiftCurrent +//// +//// Created by Tyler Thompson on 7/12/21. +//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//// // -// SwiftCurrent_NavigationLinkTests.swift -// SwiftCurrent +//import XCTest +//import SwiftUI +//import ViewInspector // -// Created by Tyler Thompson on 7/12/21. -// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//import SwiftCurrent +//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work // - -import XCTest -import SwiftUI -import ViewInspector - -import SwiftCurrent -@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -final class SwiftCurrent_NavigationLinkTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - - func testWorkflowCanBeFollowed() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - }.presentationType(.navigationLink) - } - .onFinish { _ in - expectOnFinish.fulfill() - }).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertEqual(try fr1.find(FR1.self).text().string(), "FR1 type") - XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssertTrue(try fr1.find(ViewType.NavigationLink.self).isActive()) - try fr1.find(ViewType.NavigationLink.self).find(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr2 in - XCTAssertEqual(try fr2.find(FR2.self).text().string(), "FR2 type") - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowItemsOfTheSameTypeCanBeFollowed() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR1.self) { - thenProceed(with: FR1.self) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { first in - XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) - try first.find(ViewType.NavigationLink.self).view(WorkflowItem, FR1>.self).actualView().inspect(model: model, launcher: launcher) { second in - XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) - XCTAssertFalse(try second.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try second.find(FR1.self).actualView().proceedInWorkflow()) - try second.actualView().inspect { second in - XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try second.find(ViewType.NavigationLink.self).isActive()) - try second.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { third in - XCTAssertNoThrow(try third.find(FR1.self).actualView().proceedInWorkflow()) - try third.actualView().inspect { third in - XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try second.find(ViewType.NavigationLink.self).isActive()) - } - } - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testLargeWorkflowCanBeFollowed() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - struct FR5: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR5 type") } - } - struct FR6: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR6 type") } - } - struct FR7: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR7 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) { - thenProceed(with: FR5.self) { - thenProceed(with: FR6.self) { - thenProceed(with: FR7.self) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspect { fr2 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) - try fr2.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>.self).actualView().inspect(model: model, launcher: launcher) { fr3 in - XCTAssertFalse(try fr3.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspect { fr3 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) - try fr3.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>.self).actualView().inspect(model: model, launcher: launcher) { fr4 in - XCTAssertFalse(try fr4.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - try fr4.actualView().inspect { fr4 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) - try fr4.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>.self).actualView().inspect(model: model, launcher: launcher) { fr5 in - XCTAssertFalse(try fr5.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr5.find(FR5.self).actualView().proceedInWorkflow()) - try fr5.actualView().inspect { fr5 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) - try fr5.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>.self).actualView().inspect(model: model, launcher: launcher) { fr6 in - XCTAssertFalse(try fr6.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr6.find(FR6.self).actualView().proceedInWorkflow()) - try fr6.actualView().inspect { fr6 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr6.find(ViewType.NavigationLink.self).isActive()) - try fr6.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr7 in - XCTAssertNoThrow(try fr7.find(FR7.self).actualView().proceedInWorkflow()) - try fr7.actualView().inspect { fr7 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) - XCTAssert(try fr6.find(ViewType.NavigationLink.self).isActive()) - } - } - } - } - } - } - } - } - } - } - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testNavLinkWorkflowsCanSkipTheFirstItem() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - func shouldLoad() -> Bool { false } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertThrowsError(try fr1.find(FR1.self).actualView()) - try fr1.view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in - XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in - XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testNavLinkWorkflowsCanSkipOneItemInTheMiddle() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - func shouldLoad() -> Bool { false } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR2>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) - XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testNavLinkWorkflowsCanSkipTwoItemsInTheMiddle() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - func shouldLoad() -> Bool { false } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - func shouldLoad() -> Bool { false } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - } - ).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR3>, FR2>.self).view(WorkflowItem, FR3>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr4 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) - XCTAssertThrowsError(try fr1.find(FR3.self).actualView()) - XCTAssertNoThrow(try fr4.find(FR4.self).actualView()) - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testNavLinkWorkflowsCanSkipLastItem() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - func shouldLoad() -> Bool { false } - } - - let expectOnFinish = expectation(description: "onFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) - }.presentationType(.navigationLink) - }.presentationType(.navigationLink) - } - .onFinish { _ in - expectOnFinish.fulfill() - }).inspection.inspect { fr1 in - let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue - let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue - XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in - XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testConvenienceEmbedInNavViewFunction() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - - let launcherView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self).presentationType(.navigationLink) - }.embedInNavigationView() - - let expectViewLoaded = launcherView.inspection.inspect { launcher in - let navView = try launcher.navigationView() - XCTAssert(try navView.navigationViewStyle() is StackNavigationViewStyle) - XCTAssertNoThrow(try navView.view(WorkflowItem.self, 0)) - } - ViewHosting.host(view: launcherView) - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } -} +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//final class SwiftCurrent_NavigationLinkTests: XCTestCase, View { +// override func tearDownWithError() throws { +// removeQueuedExpectations() +// } +// +// func testWorkflowCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// }.presentationType(.navigationLink) +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertEqual(try fr1.find(FR1.self).text().string(), "FR1 type") +// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssertTrue(try fr1.find(ViewType.NavigationLink.self).isActive()) +// try fr1.find(ViewType.NavigationLink.self).find(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr2 in +// XCTAssertEqual(try fr2.find(FR2.self).text().string(), "FR2 type") +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowItemsOfTheSameTypeCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR1.self) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { first in +// XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) +// try first.find(ViewType.NavigationLink.self).view(WorkflowItem, FR1>.self).actualView().inspect(model: model, launcher: launcher) { second in +// XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertFalse(try second.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try second.find(FR1.self).actualView().proceedInWorkflow()) +// try second.actualView().inspect { second in +// XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try second.find(ViewType.NavigationLink.self).isActive()) +// try second.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { third in +// XCTAssertNoThrow(try third.find(FR1.self).actualView().proceedInWorkflow()) +// try third.actualView().inspect { third in +// XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try second.find(ViewType.NavigationLink.self).isActive()) +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testLargeWorkflowCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// struct FR5: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR5 type") } +// } +// struct FR6: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR6 type") } +// } +// struct FR7: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR7 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) { +// thenProceed(with: FR5.self) { +// thenProceed(with: FR6.self) { +// thenProceed(with: FR7.self) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspect { fr2 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) +// try fr2.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>.self).actualView().inspect(model: model, launcher: launcher) { fr3 in +// XCTAssertFalse(try fr3.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspect { fr3 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) +// try fr3.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>.self).actualView().inspect(model: model, launcher: launcher) { fr4 in +// XCTAssertFalse(try fr4.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// try fr4.actualView().inspect { fr4 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) +// try fr4.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>.self).actualView().inspect(model: model, launcher: launcher) { fr5 in +// XCTAssertFalse(try fr5.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr5.find(FR5.self).actualView().proceedInWorkflow()) +// try fr5.actualView().inspect { fr5 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) +// try fr5.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>.self).actualView().inspect(model: model, launcher: launcher) { fr6 in +// XCTAssertFalse(try fr6.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr6.find(FR6.self).actualView().proceedInWorkflow()) +// try fr6.actualView().inspect { fr6 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr6.find(ViewType.NavigationLink.self).isActive()) +// try fr6.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr7 in +// XCTAssertNoThrow(try fr7.find(FR7.self).actualView().proceedInWorkflow()) +// try fr7.actualView().inspect { fr7 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) +// XCTAssert(try fr6.find(ViewType.NavigationLink.self).isActive()) +// } +// } +// } +// } +// } +// } +// } +// } +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testNavLinkWorkflowsCanSkipTheFirstItem() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertThrowsError(try fr1.find(FR1.self).actualView()) +// try fr1.view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in +// XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in +// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testNavLinkWorkflowsCanSkipOneItemInTheMiddle() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR2>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testNavLinkWorkflowsCanSkipTwoItemsInTheMiddle() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// } +// ).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR3>, FR2>.self).view(WorkflowItem, FR3>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr4 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) +// XCTAssertThrowsError(try fr1.find(FR3.self).actualView()) +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView()) +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testNavLinkWorkflowsCanSkipLastItem() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// func shouldLoad() -> Bool { false } +// } +// +// let expectOnFinish = expectation(description: "onFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) +// }.presentationType(.navigationLink) +// }.presentationType(.navigationLink) +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in +// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testConvenienceEmbedInNavViewFunction() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// +// let launcherView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self).presentationType(.navigationLink) +// }.embedInNavigationView() +// +// let expectViewLoaded = launcherView.inspection.inspect { launcher in +// let navView = try launcher.navigationView() +// XCTAssert(try navView.navigationViewStyle() is StackNavigationViewStyle) +// XCTAssertNoThrow(try navView.view(WorkflowItem.self, 0)) +// } +// ViewHosting.host(view: launcherView) +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +//} diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift index e8f8d57e3..a61a43c7b 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift @@ -1,742 +1,742 @@ +//// +//// SwiftCurrent_SwiftUIConsumerTests.swift +//// SwiftCurrent +//// +//// Created by Tyler Thompson on 7/12/21. +//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//// // -// SwiftCurrent_SwiftUIConsumerTests.swift -// SwiftCurrent -// -// Created by Tyler Thompson on 7/12/21. -// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -// - -import XCTest -import SwiftUI -import ViewInspector - -import SwiftCurrent -@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - - func testWorkflowCanBeFollowed() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - .onFinish { _ in - expectOnFinish.fulfill() - }).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowCanHaveMultipleOnFinishClosures() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - let expectOnFinish1 = expectation(description: "OnFinish1 called") - let expectOnFinish2 = expectation(description: "OnFinish2 called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) - } - .onFinish { _ in - expectOnFinish1.fulfill() - }.onFinish { _ in - expectOnFinish2.fulfill() - }).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - } - - wait(for: [expectOnFinish1, expectOnFinish2, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowCanFinishMultipleTimes() throws { - throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - let expectOnFinish1 = expectation(description: "OnFinish1 called") - let expectOnFinish2 = expectation(description: "OnFinish2 called") - var showWorkflow = Binding(wrappedValue: true) - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: showWorkflow) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - .onFinish { _ in - showWorkflow.wrappedValue = false - showWorkflow.update() - }).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - showWorkflow.wrappedValue = true - showWorkflow.update() - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - showWorkflow.wrappedValue = true - showWorkflow.update() - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - } - - wait(for: [expectOnFinish1, expectOnFinish2, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowPassesArgumentsToTheFirstItem() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - let stringProperty: String - init(with: String) { - self.stringProperty = with - } - var body: some View { Text("FR1 type") } - } - let expected = UUID().uuidString - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true), startingArgs: expected) { - thenProceed(with: FR1.self) - }) - .inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().stringProperty, expected) - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowPassesArgumentsToTheFirstItem_WhenThatFirstItemTakesInAnyWorkflowPassedArgs() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - let property: AnyWorkflow.PassedArgs - init(with: AnyWorkflow.PassedArgs) { - self.property = with - } - var body: some View { Text("FR1 type") } - } - let expected = UUID().uuidString - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true), startingArgs: expected) { - thenProceed(with: FR1.self) { - thenProceed(with: FR1.self) - } - }).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property.extractArgs(defaultValue: nil) as? String, expected) - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowPassesArgumentsToTheFirstItem_WhenThatFirstItemTakesInAnyWorkflowPassedArgs_AndTheLaunchArgsAreAnyWorkflowPassedArgs() throws { - struct FR1: View, FlowRepresentable, Inspectable { - typealias WorkflowOutput = AnyWorkflow.PassedArgs - var _workflowPointer: AnyFlowRepresentable? - let property: AnyWorkflow.PassedArgs - init(with: AnyWorkflow.PassedArgs) { - self.property = with - } - var body: some View { Text("FR1 type") } - } - let expected = UUID().uuidString - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true), startingArgs: AnyWorkflow.PassedArgs.args(expected)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR1.self) - } - }).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property.extractArgs(defaultValue: nil) as? String, expected) - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowPassesArgumentsToAllItems() throws { - struct FR1: View, FlowRepresentable, Inspectable { - typealias WorkflowOutput = Int - var _workflowPointer: AnyFlowRepresentable? - let property: String - init(with: String) { - self.property = with - } - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - typealias WorkflowOutput = Bool - var _workflowPointer: AnyFlowRepresentable? - let property: Int - init(with: Int) { - self.property = with - } - var body: some View { Text("FR1 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - typealias WorkflowOutput = String - var _workflowPointer: AnyFlowRepresentable? - let property: Bool - init(with: Bool) { - self.property = with - } - var body: some View { Text("FR1 type") } - } - let expectedFR1 = UUID().uuidString - let expectedFR2 = Int.random(in: 1...10) - let expectedFR3 = Bool.random() - let expectedEnd = UUID().uuidString - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedFR1) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) - } - } - } - .onFinish { - XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedEnd) - }).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property, expectedFR1) - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow(expectedFR2)) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR2.self).actualView().property, expectedFR2) - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow(expectedFR3)) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR3.self).actualView().property, expectedFR3) - XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow(expectedEnd)) - } - } - } - - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testLargeWorkflowCanBeFollowed() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - struct FR5: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR5 type") } - } - struct FR6: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR6 type") } - } - struct FR7: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR7 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) { - thenProceed(with: FR5.self) { - thenProceed(with: FR6.self) { - thenProceed(with: FR7.self) - } - } - } - } - } - } - } - ).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR5.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR6.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR7.self).actualView().proceedInWorkflow()) - } - } - } - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowOnlyShowsOneViewAtATime() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR2.self) - } - } - } - } - ).inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertNoThrow(try fr4.find(FR2.self).actualView().proceedInWorkflow()) - } - } - } - XCTAssertThrowsError(try fr1.find(ViewType.Text.self, skipFound: 1)) - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testMovingBiDirectionallyInAWorkflow() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - struct FR3: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type") } - } - struct FR4: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR4 type") } - } - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) { - thenProceed(with: FR4.self) - } - } - } - } - ).inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().backUpInWorkflow()) - try fr1.actualView().inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) - try fr2.actualView().inspect { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - try fr2.actualView().inspectWrapped { fr3 in - XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) - try fr3.actualView().inspectWrapped { fr4 in - XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) - } - } - } - } - } - } - } - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowSetsBindingBooleanToFalseWhenAbandoned() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - let isLaunched = Binding(wrappedValue: true) - let expectOnAbandon = expectation(description: "OnAbandon called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: isLaunched) { - thenProceed(with: FR1.self)} - .onAbandon { - XCTAssertFalse(isLaunched.wrappedValue) - expectOnAbandon.fulfill() - }).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().workflow?.abandon()) - XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) - } - - wait(for: [expectOnAbandon, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowCanHaveMultipleOnAbandonCallbacks() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - let isLaunched = Binding(wrappedValue: true) - let expectOnAbandon1 = expectation(description: "OnAbandon1 called") - let expectOnAbandon2 = expectation(description: "OnAbandon2 called") - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: isLaunched) { - thenProceed(with: FR1.self) - } - .onAbandon { - XCTAssertFalse(isLaunched.wrappedValue) - expectOnAbandon1.fulfill() - }.onAbandon { - XCTAssertFalse(isLaunched.wrappedValue) - expectOnAbandon2.fulfill() - }).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().workflow?.abandon()) - XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) - } - - wait(for: [expectOnAbandon1, expectOnAbandon2, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowCanHaveModifiers() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - - func customModifier() -> Self { self } - } - - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self).applyModifiers { $0.customModifier().background(Color.blue) - } - } - ).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).background()) - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowRelaunchesWhenSubsequentlyLaunched() throws { - throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - - func customModifier() -> Self { self } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - - let binding = Binding(wrappedValue: true) - let workflowView = WorkflowLauncher(isLaunched: binding) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - - binding.wrappedValue = false - XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) - XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) - - binding.wrappedValue = true - XCTAssertNoThrow(try viewUnderTest.callOnChange(newValue: false)) - XCTAssertNoThrow(try viewUnderTest.find(FR1.self)) - XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) - } - - wait(for: [expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowRelaunchesWhenAbandoned_WithAConstantOfTrue() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - - func abandon() { - workflow?.abandon() - } - } - let onFinishCalled = expectation(description: "onFinish Called") - - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - .onFinish { _ in - onFinishCalled.fulfill() - } - - let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().abandon()) - XCTAssertThrowsError(try fr2.find(FR2.self)) - try fr1.actualView().inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) - try fr1.actualView().inspectWrapped { fr2 in - XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) - } - } - } - } - - wait(for: [expectViewLoaded, onFinishCalled], timeout: TestConstant.timeout) - } - - func testWorkflowCanHaveAPassthroughRepresentable() throws { - struct FR1: View, FlowRepresentable, Inspectable { - typealias WorkflowOutput = AnyWorkflow.PassedArgs - var _workflowPointer: AnyFlowRepresentable? - private let data: AnyWorkflow.PassedArgs - var body: some View { Text("FR1 type") } - - init(with data: AnyWorkflow.PassedArgs) { - self.data = data - } - } - struct FR2: View, FlowRepresentable, Inspectable { - init(with str: String) { } - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectedArgs = UUID().uuidString - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - .onFinish { _ in - expectOnFinish.fulfill() - }).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow(.args(expectedArgs))) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowCanConvertAnyArgsToCorrectTypeForFirstItem() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - let data: String - - var body: some View { Text("FR1 type") } - - init(with data: String) { - self.data = data - } - } - struct FR2: View, FlowRepresentable, Inspectable { - init(with str: String) { } - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectedArgs = UUID().uuidString - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true), startingArgs: AnyWorkflow.PassedArgs.args(expectedArgs)) { - thenProceed(with: FR1.self) - } - .onFinish { _ in - expectOnFinish.fulfill() - }).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") - XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().data, expectedArgs) - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowCanHaveAPassthroughRepresentableInTheMiddle() throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - typealias WorkflowOutput = AnyWorkflow.PassedArgs - var _workflowPointer: AnyFlowRepresentable? - private let data: AnyWorkflow.PassedArgs - var body: some View { Text("FR2 type") } - - init(with data: AnyWorkflow.PassedArgs) { - self.data = data - } - } - struct FR3: View, FlowRepresentable, Inspectable { - let str: String - init(with str: String) { - self.str = str - } - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR3 type, \(str)") } - } - let expectOnFinish = expectation(description: "OnFinish called") - let expectedArgs = UUID().uuidString - let expectViewLoaded = ViewHosting.loadView( - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) { - thenProceed(with: FR3.self) - } - } - } - .onFinish { _ in - expectOnFinish.fulfill() - }).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") - XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") - XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow(.args(expectedArgs))) - try viewUnderTest.actualView().inspectWrapped { viewUnderTest in - XCTAssertEqual(try viewUnderTest.find(FR3.self).text().string(), "FR3 type, \(expectedArgs)") - XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) - } - } - } - - wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) - } - - func testWorkflowCorrectlyHandlesState() throws { - struct FR1: View, FlowRepresentable { - weak var _workflowPointer: AnyFlowRepresentable? - - var body: some View { - Button("Proceed") { proceedInWorkflow() } - } - } - - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) - } - - typealias WorkflowViewContent = State> - let content = try XCTUnwrap(Mirror(reflecting: workflowView).descendant("_content") as? WorkflowViewContent) - - // Note: Only add to these exceptions if you are *certain* the property should not be @State. Err on the side of the property being @State - let exceptions = ["_model", "_launcher", "_location", "_value", "inspection", "_presentation"] - - let mirror = Mirror(reflecting: content.wrappedValue) - - XCTAssertGreaterThan(mirror.children.count, 0) - - mirror.children.forEach { - guard let label = $0.label, !exceptions.contains(label) else { return } - XCTAssert($0.value is StateIdentifiable, "Property named: \(label) was note @State") - } - } - - func testWorkflowCanHaveADelayedLaunch() throws { - struct FR1: View, FlowRepresentable, Inspectable { - weak var _workflowPointer: AnyFlowRepresentable? - - var body: some View { - Button("Proceed") { proceedInWorkflow() } - } - } - - struct Wrapper: View, Inspectable { - @State var showingWorkflow = false - let inspection = Inspection() - var body: some View { - VStack { - Button("") { showingWorkflow = true } - WorkflowLauncher(isLaunched: $showingWorkflow) { - thenProceed(with: FR1.self) - } - } - .onReceive(inspection.notice) { inspection.visit(self, $0) } - } - } - - let exp = ViewHosting.loadView(Wrapper()).inspection.inspect { view in - let stack = try view.vStack() - let launcher = try stack.view(WorkflowLauncher>.self, 1) - XCTAssertThrowsError(try launcher.view(WorkflowItem.self)) - XCTAssertNoThrow(try stack.button(0).tap()) - XCTAssertNoThrow(try launcher.view(WorkflowItem.self)) - } - - wait(for: [exp], timeout: TestConstant.timeout) - } -} - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -protocol StateIdentifiable { } - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -extension State: StateIdentifiable { - -} +//import XCTest +//import SwiftUI +//import ViewInspector +// +//import SwiftCurrent +//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { +// override func tearDownWithError() throws { +// removeQueuedExpectations() +// } +// +// func testWorkflowCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowCanHaveMultipleOnFinishClosures() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// let expectOnFinish1 = expectation(description: "OnFinish1 called") +// let expectOnFinish2 = expectation(description: "OnFinish2 called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) +// } +// .onFinish { _ in +// expectOnFinish1.fulfill() +// }.onFinish { _ in +// expectOnFinish2.fulfill() +// }).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// } +// +// wait(for: [expectOnFinish1, expectOnFinish2, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowCanFinishMultipleTimes() throws { +// throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// let expectOnFinish1 = expectation(description: "OnFinish1 called") +// let expectOnFinish2 = expectation(description: "OnFinish2 called") +// var showWorkflow = Binding(wrappedValue: true) +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: showWorkflow) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// .onFinish { _ in +// showWorkflow.wrappedValue = false +// showWorkflow.update() +// }).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// showWorkflow.wrappedValue = true +// showWorkflow.update() +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// showWorkflow.wrappedValue = true +// showWorkflow.update() +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// } +// +// wait(for: [expectOnFinish1, expectOnFinish2, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowPassesArgumentsToTheFirstItem() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// let stringProperty: String +// init(with: String) { +// self.stringProperty = with +// } +// var body: some View { Text("FR1 type") } +// } +// let expected = UUID().uuidString +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true), startingArgs: expected) { +// thenProceed(with: FR1.self) +// }) +// .inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().stringProperty, expected) +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowPassesArgumentsToTheFirstItem_WhenThatFirstItemTakesInAnyWorkflowPassedArgs() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// let property: AnyWorkflow.PassedArgs +// init(with: AnyWorkflow.PassedArgs) { +// self.property = with +// } +// var body: some View { Text("FR1 type") } +// } +// let expected = UUID().uuidString +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true), startingArgs: expected) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR1.self) +// } +// }).inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property.extractArgs(defaultValue: nil) as? String, expected) +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowPassesArgumentsToTheFirstItem_WhenThatFirstItemTakesInAnyWorkflowPassedArgs_AndTheLaunchArgsAreAnyWorkflowPassedArgs() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// typealias WorkflowOutput = AnyWorkflow.PassedArgs +// var _workflowPointer: AnyFlowRepresentable? +// let property: AnyWorkflow.PassedArgs +// init(with: AnyWorkflow.PassedArgs) { +// self.property = with +// } +// var body: some View { Text("FR1 type") } +// } +// let expected = UUID().uuidString +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true), startingArgs: AnyWorkflow.PassedArgs.args(expected)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR1.self) +// } +// }).inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property.extractArgs(defaultValue: nil) as? String, expected) +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowPassesArgumentsToAllItems() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// typealias WorkflowOutput = Int +// var _workflowPointer: AnyFlowRepresentable? +// let property: String +// init(with: String) { +// self.property = with +// } +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// typealias WorkflowOutput = Bool +// var _workflowPointer: AnyFlowRepresentable? +// let property: Int +// init(with: Int) { +// self.property = with +// } +// var body: some View { Text("FR1 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// typealias WorkflowOutput = String +// var _workflowPointer: AnyFlowRepresentable? +// let property: Bool +// init(with: Bool) { +// self.property = with +// } +// var body: some View { Text("FR1 type") } +// } +// let expectedFR1 = UUID().uuidString +// let expectedFR2 = Int.random(in: 1...10) +// let expectedFR3 = Bool.random() +// let expectedEnd = UUID().uuidString +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedFR1) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) +// } +// } +// } +// .onFinish { +// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedEnd) +// }).inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property, expectedFR1) +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow(expectedFR2)) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR2.self).actualView().property, expectedFR2) +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow(expectedFR3)) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR3.self).actualView().property, expectedFR3) +// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow(expectedEnd)) +// } +// } +// } +// +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testLargeWorkflowCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// struct FR5: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR5 type") } +// } +// struct FR6: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR6 type") } +// } +// struct FR7: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR7 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) { +// thenProceed(with: FR5.self) { +// thenProceed(with: FR6.self) { +// thenProceed(with: FR7.self) +// } +// } +// } +// } +// } +// } +// } +// ).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR5.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR6.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR7.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowOnlyShowsOneViewAtATime() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR2.self) +// } +// } +// } +// } +// ).inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertNoThrow(try fr4.find(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// } +// XCTAssertThrowsError(try fr1.find(ViewType.Text.self, skipFound: 1)) +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testMovingBiDirectionallyInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// } +// } +// } +// ).inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().backUpInWorkflow()) +// try fr1.actualView().inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) +// try fr2.actualView().inspect { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowSetsBindingBooleanToFalseWhenAbandoned() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// let isLaunched = Binding(wrappedValue: true) +// let expectOnAbandon = expectation(description: "OnAbandon called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: isLaunched) { +// thenProceed(with: FR1.self)} +// .onAbandon { +// XCTAssertFalse(isLaunched.wrappedValue) +// expectOnAbandon.fulfill() +// }).inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().workflow?.abandon()) +// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) +// } +// +// wait(for: [expectOnAbandon, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowCanHaveMultipleOnAbandonCallbacks() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// let isLaunched = Binding(wrappedValue: true) +// let expectOnAbandon1 = expectation(description: "OnAbandon1 called") +// let expectOnAbandon2 = expectation(description: "OnAbandon2 called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: isLaunched) { +// thenProceed(with: FR1.self) +// } +// .onAbandon { +// XCTAssertFalse(isLaunched.wrappedValue) +// expectOnAbandon1.fulfill() +// }.onAbandon { +// XCTAssertFalse(isLaunched.wrappedValue) +// expectOnAbandon2.fulfill() +// }).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().workflow?.abandon()) +// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) +// } +// +// wait(for: [expectOnAbandon1, expectOnAbandon2, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowCanHaveModifiers() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// +// func customModifier() -> Self { self } +// } +// +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self).applyModifiers { $0.customModifier().background(Color.blue) +// } +// } +// ).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).background()) +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowRelaunchesWhenSubsequentlyLaunched() throws { +// throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// +// func customModifier() -> Self { self } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// +// let binding = Binding(wrappedValue: true) +// let workflowView = WorkflowLauncher(isLaunched: binding) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// +// binding.wrappedValue = false +// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) +// XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) +// +// binding.wrappedValue = true +// XCTAssertNoThrow(try viewUnderTest.callOnChange(newValue: false)) +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self)) +// XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowRelaunchesWhenAbandoned_WithAConstantOfTrue() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// +// func abandon() { +// workflow?.abandon() +// } +// } +// let onFinishCalled = expectation(description: "onFinish Called") +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// .onFinish { _ in +// onFinishCalled.fulfill() +// } +// +// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().abandon()) +// XCTAssertThrowsError(try fr2.find(FR2.self)) +// try fr1.actualView().inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded, onFinishCalled], timeout: TestConstant.timeout) +// } +// +// func testWorkflowCanHaveAPassthroughRepresentable() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// typealias WorkflowOutput = AnyWorkflow.PassedArgs +// var _workflowPointer: AnyFlowRepresentable? +// private let data: AnyWorkflow.PassedArgs +// var body: some View { Text("FR1 type") } +// +// init(with data: AnyWorkflow.PassedArgs) { +// self.data = data +// } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// init(with str: String) { } +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectedArgs = UUID().uuidString +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) +// } +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow(.args(expectedArgs))) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowCanConvertAnyArgsToCorrectTypeForFirstItem() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// let data: String +// +// var body: some View { Text("FR1 type") } +// +// init(with data: String) { +// self.data = data +// } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// init(with str: String) { } +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectedArgs = UUID().uuidString +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true), startingArgs: AnyWorkflow.PassedArgs.args(expectedArgs)) { +// thenProceed(with: FR1.self) +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") +// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().data, expectedArgs) +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowCanHaveAPassthroughRepresentableInTheMiddle() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// typealias WorkflowOutput = AnyWorkflow.PassedArgs +// var _workflowPointer: AnyFlowRepresentable? +// private let data: AnyWorkflow.PassedArgs +// var body: some View { Text("FR2 type") } +// +// init(with data: AnyWorkflow.PassedArgs) { +// self.data = data +// } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// let str: String +// init(with str: String) { +// self.str = str +// } +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type, \(str)") } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectedArgs = UUID().uuidString +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) +// } +// } +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow(.args(expectedArgs))) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertEqual(try viewUnderTest.find(FR3.self).text().string(), "FR3 type, \(expectedArgs)") +// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testWorkflowCorrectlyHandlesState() throws { +// struct FR1: View, FlowRepresentable { +// weak var _workflowPointer: AnyFlowRepresentable? +// +// var body: some View { +// Button("Proceed") { proceedInWorkflow() } +// } +// } +// +// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) +// } +// +// typealias WorkflowViewContent = State> +// let content = try XCTUnwrap(Mirror(reflecting: workflowView).descendant("_content") as? WorkflowViewContent) +// +// // Note: Only add to these exceptions if you are *certain* the property should not be @State. Err on the side of the property being @State +// let exceptions = ["_model", "_launcher", "_location", "_value", "inspection", "_presentation"] +// +// let mirror = Mirror(reflecting: content.wrappedValue) +// +// XCTAssertGreaterThan(mirror.children.count, 0) +// +// mirror.children.forEach { +// guard let label = $0.label, !exceptions.contains(label) else { return } +// XCTAssert($0.value is StateIdentifiable, "Property named: \(label) was note @State") +// } +// } +// +// func testWorkflowCanHaveADelayedLaunch() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// weak var _workflowPointer: AnyFlowRepresentable? +// +// var body: some View { +// Button("Proceed") { proceedInWorkflow() } +// } +// } +// +// struct Wrapper: View, Inspectable { +// @State var showingWorkflow = false +// let inspection = Inspection() +// var body: some View { +// VStack { +// Button("") { showingWorkflow = true } +// WorkflowLauncher(isLaunched: $showingWorkflow) { +// thenProceed(with: FR1.self) +// } +// } +// .onReceive(inspection.notice) { inspection.visit(self, $0) } +// } +// } +// +// let exp = ViewHosting.loadView(Wrapper()).inspection.inspect { view in +// let stack = try view.vStack() +// let launcher = try stack.view(WorkflowLauncher>.self, 1) +// XCTAssertThrowsError(try launcher.view(WorkflowItem.self)) +// XCTAssertNoThrow(try stack.button(0).tap()) +// XCTAssertNoThrow(try launcher.view(WorkflowItem.self)) +// } +// +// wait(for: [exp], timeout: TestConstant.timeout) +// } +//} +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//protocol StateIdentifiable { } +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//extension State: StateIdentifiable { +// +//} diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index 80f400b53..113b9a568 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -12,6 +12,58 @@ import XCTest @testable import SwiftCurrent_SwiftUI +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension View where Self: Inspectable { + func hostAndInspect(with emmisary: KeyPath) async throws -> InspectableView> where E.V == Self { + DispatchQueue.main.async { ViewHosting.host(view: self) } + return try await self[keyPath: emmisary].inspect() + } +} + +@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +extension InspectableView where View: CustomViewType & SingleViewContent { + func extractWorkflowItem() async throws -> InspectableView>> where View.T == WorkflowLauncher> { + let mirror = Mirror(reflecting: try actualView()) + let model = try XCTUnwrap(mirror.descendant("_model") as? StateObject) + let launcher = try XCTUnwrap(mirror.descendant("_launcher") as? StateObject) + let actual = try view(WorkflowItem.self).actualView() + + DispatchQueue.main.async { + ViewHosting.host(view: actual + .environmentObject(model.wrappedValue) + .environmentObject(launcher.wrappedValue)) + } + + return try await actual.inspection.inspect() + } + + func extractWrappedWorkflowItem() async throws -> InspectableView>> where View.T == WorkflowItem, PC> { + let wrapped = try await actualView().getWrappedView() + return try find(type(of: wrapped)) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension InspectionEmissary where V: View & Inspectable { + func inspect(after delay: TimeInterval = 0, + function: String = #function, + file: StaticString = #file, + line: UInt = #line) async throws -> InspectableView> { + try await withCheckedThrowingContinuation { continuation in + do { + var v: InspectableView>? + let exp = self.inspect(after: delay, function: function, file: file, line: line) { view in + v = view + } + XCTWaiter().wait(for: [exp], timeout: TestConstant.timeout) + continuation.resume(returning: try XCTUnwrap(v, "view type \(String(describing: V.self)) not inspected")) + } catch { + continuation.resume(throwing: error) + } + } + } +} + @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) extension ViewHosting { static func loadView(_ view: V) -> V { diff --git a/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift index 69e5d4868..55f13278a 100644 --- a/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift @@ -14,6 +14,10 @@ import ViewInspector @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) extension WorkflowItem { + func getWrappedView() throws -> Wrapped { + try XCTUnwrap((Mirror(reflecting: self).descendant("_wrapped") as? State)?.wrappedValue) + } + @discardableResult func inspectWrapped(function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation where Wrapped == WorkflowItem { let wrapped = try XCTUnwrap((Mirror(reflecting: self).descendant("_wrapped") as? State)?.wrappedValue) return try wrapped.inspect(function: function, file: file, line: line, inspection: inspection) From 633e5e7c557e13edd2cd3d9986e97868da5134e2 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Thu, 3 Feb 2022 23:00:47 -0700 Subject: [PATCH 02/37] [async-swiftui-tests] - try to explicitly run on iOS 15 - TT --- .github/fastlane/Fastfile | 1 + .../GenericConstraintTests.swift | 95 +++++++++---------- 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/.github/fastlane/Fastfile b/.github/fastlane/Fastfile index 93f97c7c5..8726d2ed8 100644 --- a/.github/fastlane/Fastfile +++ b/.github/fastlane/Fastfile @@ -13,6 +13,7 @@ platform :ios do scheme: 'SwiftCurrent', workspace: '../SwiftCurrent.xcworkspace', derived_data_path: "~/Library/Developer/Xcode/DerivedData", + devices: ['platform=iOS Simulator,name=iPhone 13 Pro Max,OS=15.0'] ) end diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index f67948774..64b73c8fb 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -151,55 +151,52 @@ final class GenericConstraintTests: XCTestCase, View { let view = try await workflowView.actualView().getWrappedView() XCTAssertNoThrow(try workflowView.find(type(of: view)).find(FR2.self)) } -// -// func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { .removedAfterProceeding } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + + func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { .removedAfterProceeding } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } // // func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { // struct FR1: FlowRepresentable, View, Inspectable { From ef407072f6014712fe2fda306f56878e09cde941 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Thu, 3 Feb 2022 23:03:33 -0700 Subject: [PATCH 03/37] [async-swiftui-tests] - The default simulator was already running 15 it seems, but the tests needed to up the iOS version - TT --- .github/fastlane/Fastfile | 1 - Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/fastlane/Fastfile b/.github/fastlane/Fastfile index 8726d2ed8..93f97c7c5 100644 --- a/.github/fastlane/Fastfile +++ b/.github/fastlane/Fastfile @@ -13,7 +13,6 @@ platform :ios do scheme: 'SwiftCurrent', workspace: '../SwiftCurrent.xcworkspace', derived_data_path: "~/Library/Developer/Xcode/DerivedData", - devices: ['platform=iOS Simulator,name=iPhone 13 Pro Max,OS=15.0'] ) end diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 64b73c8fb..38da13ce8 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -31,7 +31,7 @@ extension FlowRepresentable { } } -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) final class GenericConstraintTests: XCTestCase, View { override func tearDownWithError() throws { removeQueuedExpectations() From cc99f9a2e1e41adbab269134aa6b4f9d8c33b89e Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Thu, 3 Feb 2022 23:10:40 -0700 Subject: [PATCH 04/37] [async-swiftui-tests] - Fixed availability in the other problem areas and got rid of queued expectations entirely - TT --- .../AnyFlowRepresentableViewTests.swift | 4 - .../AnyWorkflowTests.swift | 4 - .../GenericConstraintTests.swift | 150 +++++++++--------- .../SwiftUILaunchStyleAdditionTests.swift | 4 - .../TestExtensions/XCTestCaseExtensions.swift | 12 -- .../ViewInspector/ViewHostingExtensions.swift | 6 +- .../WorkflowItemExtensions.swift | 36 ++--- .../WorkflowItemTests.swift | 4 - .../WorkflowViewModelTests.swift | 4 - 9 files changed, 92 insertions(+), 132 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/AnyFlowRepresentableViewTests.swift b/Tests/SwiftCurrent_SwiftUITests/AnyFlowRepresentableViewTests.swift index e731e150a..8964a7897 100644 --- a/Tests/SwiftCurrent_SwiftUITests/AnyFlowRepresentableViewTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/AnyFlowRepresentableViewTests.swift @@ -15,10 +15,6 @@ import SwiftCurrent @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) final class AnyFlowRepresentableViewTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - func testAnyFlowRepresentableViewDoesNotCreate_StrongRetainCycle() { var afrv: AnyFlowRepresentableView? weak var ref: AnyFlowRepresentableView? diff --git a/Tests/SwiftCurrent_SwiftUITests/AnyWorkflowTests.swift b/Tests/SwiftCurrent_SwiftUITests/AnyWorkflowTests.swift index f8d2f0bca..7c2db3d48 100644 --- a/Tests/SwiftCurrent_SwiftUITests/AnyWorkflowTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/AnyWorkflowTests.swift @@ -14,10 +14,6 @@ import SwiftCurrent_SwiftUI @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) final class AnyWorkflowTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - func testAbandonDoesNotBLOWUP() { let wf = Workflow(FR.self) AnyWorkflow(wf).abandon() diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 38da13ce8..d98303f92 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -33,10 +33,6 @@ extension FlowRepresentable { @available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) final class GenericConstraintTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - // MARK: Generic Initializer Tests // MARK: Input Type == Never @@ -197,81 +193,77 @@ final class GenericConstraintTests: XCTestCase, View { let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } -// -// func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { .removedAfterProceeding } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + + func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { .removedAfterProceeding } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } // // func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { // struct FR1: FlowRepresentable, View, Inspectable { diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftUILaunchStyleAdditionTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftUILaunchStyleAdditionTests.swift index 58869e801..91c3d2c25 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftUILaunchStyleAdditionTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftUILaunchStyleAdditionTests.swift @@ -15,10 +15,6 @@ import SwiftUI @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) final class LaunchStyleAdditionTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - func testPresentationTypeInitializer() { XCTAssertNil(LaunchStyle.SwiftUI.PresentationType(rawValue: .new)) XCTAssertEqual(LaunchStyle.SwiftUI.PresentationType(rawValue: .default), .default) diff --git a/Tests/SwiftCurrent_SwiftUITests/TestExtensions/XCTestCaseExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/TestExtensions/XCTestCaseExtensions.swift index 18a3db6d5..482a616e2 100644 --- a/Tests/SwiftCurrent_SwiftUITests/TestExtensions/XCTestCaseExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/TestExtensions/XCTestCaseExtensions.swift @@ -9,18 +9,6 @@ import SwiftUI import XCTest -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -extension XCTestCase { - static var queuedExpectations: [XCTestExpectation] = [] - - func removeQueuedExpectations() { - while let e = Self.queuedExpectations.first { - wait(for: [e], timeout: TestConstant.timeout) - Self.queuedExpectations.removeFirst() - } - } -} - @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) extension View where Self: XCTestCase { public var body: some View { EmptyView() } diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index 113b9a568..b5ad8e89f 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -12,7 +12,7 @@ import XCTest @testable import SwiftCurrent_SwiftUI -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 15.0, macOS 10.15, tvOS 13.0, *) extension View where Self: Inspectable { func hostAndInspect(with emmisary: KeyPath) async throws -> InspectableView> where E.V == Self { DispatchQueue.main.async { ViewHosting.host(view: self) } @@ -20,7 +20,7 @@ extension View where Self: Inspectable { } } -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) extension InspectableView where View: CustomViewType & SingleViewContent { func extractWorkflowItem() async throws -> InspectableView>> where View.T == WorkflowLauncher> { let mirror = Mirror(reflecting: try actualView()) @@ -43,7 +43,7 @@ extension InspectableView where View: CustomViewType & SingleViewContent { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 15.0, macOS 10.15, tvOS 13.0, *) public extension InspectionEmissary where V: View & Inspectable { func inspect(after delay: TimeInterval = 0, function: String = #function, diff --git a/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift index 55f13278a..ac6ffff93 100644 --- a/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift @@ -18,23 +18,23 @@ extension WorkflowItem { try XCTUnwrap((Mirror(reflecting: self).descendant("_wrapped") as? State)?.wrappedValue) } - @discardableResult func inspectWrapped(function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation where Wrapped == WorkflowItem { - let wrapped = try XCTUnwrap((Mirror(reflecting: self).descendant("_wrapped") as? State)?.wrappedValue) - return try wrapped.inspect(function: function, file: file, line: line, inspection: inspection) - } - - @discardableResult func inspect(function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation { - // Waiting for 0.0 seems insane but think about it like "We are waiting for this command to get off the stack" - // Then quit thinking about it, know it was deliberate, and move on. - let expectation = self.inspection.inspect(after: 0, function: function, file: file, line: line) { - try inspection($0) - } - XCTestCase.queuedExpectations.append(expectation) - return expectation - } - - @discardableResult func inspect(model: WorkflowViewModel, launcher: Launcher, function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation { - try ViewHosting.loadView(self, model: model, launcher: launcher).inspect(function: function, file: file, line: line, inspection: inspection) - } +// @discardableResult func inspectWrapped(function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation where Wrapped == WorkflowItem { +// let wrapped = try XCTUnwrap((Mirror(reflecting: self).descendant("_wrapped") as? State)?.wrappedValue) +// return try wrapped.inspect(function: function, file: file, line: line, inspection: inspection) +// } +// +// @discardableResult func inspect(function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation { +// // Waiting for 0.0 seems insane but think about it like "We are waiting for this command to get off the stack" +// // Then quit thinking about it, know it was deliberate, and move on. +// let expectation = self.inspection.inspect(after: 0, function: function, file: file, line: line) { +// try inspection($0) +// } +// XCTestCase.queuedExpectations.append(expectation) +// return expectation +// } +// +// @discardableResult func inspect(model: WorkflowViewModel, launcher: Launcher, function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation { +// try ViewHosting.loadView(self, model: model, launcher: launcher).inspect(function: function, file: file, line: line, inspection: inspection) +// } } diff --git a/Tests/SwiftCurrent_SwiftUITests/WorkflowItemTests.swift b/Tests/SwiftCurrent_SwiftUITests/WorkflowItemTests.swift index fbcfab500..c5ac36f4a 100644 --- a/Tests/SwiftCurrent_SwiftUITests/WorkflowItemTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/WorkflowItemTests.swift @@ -14,10 +14,6 @@ import SwiftUI @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) final class WorkflowItemTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - func testWorkflowItemThrowsFatalError_IfPersistenceCannotBeCast() throws { let item = WorkflowItem(FR.self).persistence { _ in .default diff --git a/Tests/SwiftCurrent_SwiftUITests/WorkflowViewModelTests.swift b/Tests/SwiftCurrent_SwiftUITests/WorkflowViewModelTests.swift index 977889250..1ab1a13e7 100644 --- a/Tests/SwiftCurrent_SwiftUITests/WorkflowViewModelTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/WorkflowViewModelTests.swift @@ -16,10 +16,6 @@ import SwiftCurrent_Testing @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) final class WorkflowViewModelTests: XCTestCase, View { - override func tearDownWithError() throws { - removeQueuedExpectations() - } - func testAnyWorkflowElementModelThrowsFatalError_WhenExtractCalledOnSomethingOtherThan_AnyFlowRepresentableView() throws { try XCTAssertThrowsFatalError { _ = AnyWorkflow.Element.createForTests(FR.self).extractErasedView() From d711d91d1af73b8d9fdf8f92fad930fcf97cb128 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Thu, 3 Feb 2022 23:20:59 -0700 Subject: [PATCH 05/37] [async-swiftui-tests] - Refactored a bunch more tests, theres still compiler issues in other modules but I don't care because this whole thing is just going to be slow going - TT --- .../GenericConstraintTests.swift | 374 +++++++++--------- 1 file changed, 184 insertions(+), 190 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index d98303f92..133dbdec4 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -264,196 +264,190 @@ final class GenericConstraintTests: XCTestCase, View { let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } -// -// func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { .removedAfterProceeding } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// // MARK: Input Type == AnyWorkflow.PassedArgs -// -// func testWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithAutoclosure() { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgs_PresentationTypeCanBeSetWithAutoclosure() { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self).presentationType(.navigationLink) -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().presentationType, .navigationLink) -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let expectation = self.expectation(description: "FlowPersistence closure called") -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self).persistence { -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) -// defer { expectation.fulfill() } -// return .removedAfterProceeding -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + + func testWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { .removedAfterProceeding } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + // MARK: Input Type == AnyWorkflow.PassedArgs + + func testWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithAutoclosure() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self).persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + } + + func testWhenInputIsAnyWorkflowPassedArgs_PresentationTypeCanBeSetWithAutoclosure() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self).presentationType(.navigationLink) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().presentationType, .navigationLink) + } + + func testWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let expectation = self.expectation(description: "FlowPersistence closure called") + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self).persistence { + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) + defer { expectation.fulfill() } + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + wait(for: [expectation], timeout: TestConstant.timeout) + } + + func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } // // func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { // struct FR1: FlowRepresentable, View, Inspectable { From 29e3098264bcf6ca0d7f6e3577eddfd2db3a4352 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 13:42:13 -0700 Subject: [PATCH 06/37] [async-swiftui-tests] - Got more tests refactored - TT --- .../GenericConstraintTests.swift | 739 +++++++++--------- 1 file changed, 362 insertions(+), 377 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 133dbdec4..001cd4ac7 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -448,383 +448,368 @@ final class GenericConstraintTests: XCTestCase, View { let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) -// return .removedAfterProceeding -// } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) -// return .removedAfterProceeding -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) -// return .removedAfterProceeding -// } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// // MARK: Input Type == Concrete Type -// func testWhenInputIsConcreteType_FlowPersistenceCanBeSetWithAutoclosure() { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteType_PresentationTypeCanBeSetWithAutoclosure() { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self).presentationType(.navigationLink) -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().presentationType, .navigationLink) -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteType_FlowPersistenceCanBeSetWithClosure() { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let expectation = self.expectation(description: "FlowPersistence closure called") -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self).persistence { -// XCTAssertEqual($0, expectedArgs) -// defer { expectation.fulfill() } -// return .removedAfterProceeding -// } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { -// XCTAssertEqual($0, expectedArgs) -// return .removedAfterProceeding -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + + func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + // MARK: Input Type == Concrete Type + func testWhenInputIsConcreteType_FlowPersistenceCanBeSetWithAutoclosure() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self).persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + } + + func testWhenInputIsConcreteType_PresentationTypeCanBeSetWithAutoclosure() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self).presentationType(.navigationLink) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().presentationType, .navigationLink) + } + + func testWhenInputIsConcreteType_FlowPersistenceCanBeSetWithClosure() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let expectation = self.expectation(description: "FlowPersistence closure called") + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self).persistence { + XCTAssertEqual($0, expectedArgs) + defer { expectation.fulfill() } + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + wait(for: [expectation], timeout: TestConstant.timeout) + } + + func testWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { + XCTAssertEqual($0, expectedArgs) + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } // // func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { // struct FR1: FlowRepresentable, View, Inspectable { From 7450e43e55e7b4d9a5dc8ab6f60af5154bcf867a Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 15:02:25 -0700 Subject: [PATCH 07/37] [async-swiftui-tests] - Had to re host the view after wrapping it because...reasons I dont know, view inspector made me - TT --- .../GenericConstraintTests.swift | 653 +++++++++--------- .../ViewInspector/ViewHostingExtensions.swift | 10 +- 2 files changed, 331 insertions(+), 332 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 001cd4ac7..f9ef1a958 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -810,337 +810,328 @@ final class GenericConstraintTests: XCTestCase, View { let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } -// -// func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { -// XCTAssertEqual($0, expectedArgs) -// return .removedAfterProceeding -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { -// XCTAssertEqual($0, expectedArgs) -// return .removedAfterProceeding -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence(.removedAfterProceeding) -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { -// XCTAssertEqual($0, expectedArgs) -// return .removedAfterProceeding -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// // MARK: Generic Proceed Tests -// -// // MARK: Input Type == Never -// -// func testProceedingWhenInputIsNever_FlowPersistenceCanBeSetWithAutoclosure() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsNever_FlowPersistenceCanBeSetWithClosure() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let expectation = self.expectation(description: "FlowPersistence closure called") -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self).persistence { -// defer { expectation.fulfill() } -// return .removedAfterProceeding -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// + + func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { + XCTAssertEqual($0, expectedArgs) + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { + XCTAssertEqual($0, expectedArgs) + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow("")) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow("")) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() async throws { + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { + XCTAssertEqual($0, expectedArgs) + return .removedAfterProceeding + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow("")) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + // MARK: Generic Proceed Tests + + // MARK: Input Type == Never + + func testProceedingWhenInputIsNever_FlowPersistenceCanBeSetWithAutoclosure() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self).persistence(.removedAfterProceeding) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsNever_FlowPersistenceCanBeSetWithClosure() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let expectation = self.expectation(description: "FlowPersistence closure called") + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self).persistence { + defer { expectation.fulfill() } + return .removedAfterProceeding + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) + wait(for: [expectation], timeout: TestConstant.timeout) + } + + func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnotherNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + // func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { // struct FR0: PassthroughFlowRepresentable, View, Inspectable { // var _workflowPointer: AnyFlowRepresentable? diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index b5ad8e89f..ce642839d 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -39,7 +39,15 @@ extension InspectableView where View: CustomViewType & SingleViewContent { func extractWrappedWorkflowItem() async throws -> InspectableView>> where View.T == WorkflowItem, PC> { let wrapped = try await actualView().getWrappedView() - return try find(type(of: wrapped)) + let mirror = Mirror(reflecting: try actualView()) + let model = try XCTUnwrap(mirror.descendant("_model") as? EnvironmentObject) + let launcher = try XCTUnwrap(mirror.descendant("_launcher") as? EnvironmentObject) + DispatchQueue.main.async { + ViewHosting.host(view: wrapped + .environmentObject(model.wrappedValue) + .environmentObject(launcher.wrappedValue)) + } + return try await wrapped.inspection.inspect() } } From 3b5d1d14dd8aa5cb3c2a60bc0595791431498d88 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 15:23:17 -0700 Subject: [PATCH 08/37] [async-swiftui-tests] - Added a bunch more of those generic tests - TT --- .../GenericConstraintTests.swift | 413 +++++++++--------- 1 file changed, 201 insertions(+), 212 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index f9ef1a958..9b69cd4b3 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -1132,218 +1132,207 @@ final class GenericConstraintTests: XCTestCase, View { XCTAssertNoThrow(try view.find(FR2.self)) } -// func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { .removedAfterProceeding } -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var body: some View { Text(String(describing: Self.self)) } -// var _workflowPointer: AnyFlowRepresentable? -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnotherNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { .removedAfterProceeding } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsNeverWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var body: some View { Text(String(describing: Self.self)) } + var _workflowPointer: AnyFlowRepresentable? + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } // // func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { // struct FR0: PassthroughFlowRepresentable, View, Inspectable { From c0c2597923ca23cd19f657586e35498a04aed640 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 15:36:34 -0700 Subject: [PATCH 09/37] [async-swiftui-tests] - Bunch more tests - TT --- .../GenericConstraintTests.swift | 151 +++++++++--------- 1 file changed, 73 insertions(+), 78 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 9b69cd4b3..43092b458 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -1333,84 +1333,79 @@ final class GenericConstraintTests: XCTestCase, View { let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } -// -// func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var body: some View { Text(String(describing: Self.self)) } -// var _workflowPointer: AnyFlowRepresentable? -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { -// XCTAssertEqual($0, 1) -// return .removedAfterProceeding -// } -// } -// } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + + func testProceedingWhenInputIsNeverWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var body: some View { Text(String(describing: Self.self)) } + var _workflowPointer: AnyFlowRepresentable? + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsNeverWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { + XCTAssertEqual($0, 1) + return .removedAfterProceeding + } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow(1)) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } // // // // MARK: Input Type == AnyWorkflow.PassedArgs From 37fc318a152389f11275145af5c98320d2d4b6be Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 16:01:29 -0700 Subject: [PATCH 10/37] [async-swiftui-tests] - You know I am glad we wrote all these tests but refactoring them is NOT FUN - TT --- .../GenericConstraintTests.swift | 556 +++++++++--------- 1 file changed, 270 insertions(+), 286 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 43092b458..88e209509 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -1406,292 +1406,276 @@ final class GenericConstraintTests: XCTestCase, View { XCTAssertNoThrow(try view.find(FR2.self)) XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) } -// -// -// // MARK: Input Type == AnyWorkflow.PassedArgs -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithAutoclosure() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let expectation = self.expectation(description: "FlowPersistence closure called") -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self).persistence { -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) -// defer { expectation.fulfill() } -// return .removedAfterProceeding -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.persistence { -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) -// return .removedAfterProceeding -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// try view.actualView().inspect { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) -// return .removedAfterProceeding -// } -// } -// } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + + + // MARK: Input Type == AnyWorkflow.PassedArgs + + func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithAutoclosure() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self).persistence(.removedAfterProceeding) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let expectation = self.expectation(description: "FlowPersistence closure called") + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self).persistence { + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) + defer { expectation.fulfill() } + return .removedAfterProceeding + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) + wait(for: [expectation], timeout: TestConstant.timeout) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let workflowItem = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + let view = try await workflowItem.extractWrappedWorkflowItem() + XCTAssertNoThrow(try view.find(FR2.self)) + XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.persistence { + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) + return .removedAfterProceeding + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertEqual(try wfr1.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedArgs) + return .removedAfterProceeding + } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } // // func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { // struct FR0: PassthroughFlowRepresentable, View, Inspectable { From e6bdb800abba59e5dfc48ad2f4ed443e12e69474 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 16:30:16 -0700 Subject: [PATCH 11/37] [async-swiftui-tests] - Finally got all generic constraint tests refactored - TT --- .../GenericConstraintTests.swift | 1754 ++++++++--------- 1 file changed, 849 insertions(+), 905 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 88e209509..372af1637 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -1676,909 +1676,853 @@ final class GenericConstraintTests: XCTestCase, View { XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { -// XCTAssertEqual($0, 1) -// return .removedAfterProceeding -// } -// } -// } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// // MARK: Input Type == Concrete Type -// func testCreatingMalformedWorkflowWithMismatchingConcreteTypes() throws { -// struct FR0: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// -// try XCTAssertThrowsFatalError { -// _ = WorkflowLauncher(isLaunched: .constant(true)) { -// self.thenProceed(with: FR0.self) { -// self.thenProceed(with: FR1.self).persistence(.removedAfterProceeding) -// } -// } -// } -// } -// -// func testProceedingWhenInputIsConcreteType_FlowPersistenceCanBeSetWithAutoclosure() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self).persistence(.removedAfterProceeding) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteType_FlowPersistenceCanBeSetWithClosure() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let expectation = self.expectation(description: "FlowPersistence closure called") -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self).persistence { -// XCTAssertEqual($0, expectedArgs) -// defer { expectation.fulfill() } -// return .removedAfterProceeding -// } -// } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// wait(for: [expectViewLoaded, expectation], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { .removedAfterProceeding } -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: Int) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { -// XCTAssertEqual($0, 1) -// return .removedAfterProceeding -// } -// } -// } -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(1)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnyWorkflowPassedArgsItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: AnyWorkflow.PassedArgs) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testProceedingTwiceWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() throws { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnView() { -// final class FR0: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// final class FR1: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// final class FR2: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -//} -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//final class ThenProceedOnAppTests: XCTestCase, App { -// override func tearDownWithError() throws { -// removeQueuedExpectations() -// } -// -// func testThenProceedFunctionsAsExpectedOnApp() { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnApp() { -// final class FR0: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// final class FR1: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// final class FR2: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -//} -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//final class ThenProceedOnSceneTests: XCTestCase, Scene { -// override func tearDownWithError() throws { -// removeQueuedExpectations() -// } -// -// func testThenProceedFunctionsAsExpectedOnScene() { -// struct FR0: PassthroughFlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// } -// struct FR1: FlowRepresentable, View, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// struct FR2: FlowRepresentable, View, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text(String(describing: Self.self)) } -// init(with args: String) { } -// } -// let expectedArgs = UUID().uuidString -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).persistence(.removedAfterProceeding) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(FR0.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR1.self).actualView().proceedInWorkflow("")) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(FR2.self)) -// XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnScene() { -// final class FR0: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// final class FR1: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// final class FR2: UIViewController, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// } -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR0.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(ViewControllerWrapper.self)) -// } -// } -// } -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsAnyWorkflowPassedArgsWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { + XCTAssertEqual($0, 1) + return .removedAfterProceeding + } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + // MARK: Input Type == Concrete Type + func testCreatingMalformedWorkflowWithMismatchingConcreteTypes() throws { + struct FR0: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + + try XCTAssertThrowsFatalError { + _ = WorkflowLauncher(isLaunched: .constant(true)) { + self.thenProceed(with: FR0.self) { + self.thenProceed(with: FR1.self).persistence(.removedAfterProceeding) + } + } + } + } + + func testProceedingWhenInputIsConcreteType_FlowPersistenceCanBeSetWithAutoclosure() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self).persistence(.removedAfterProceeding) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteType_FlowPersistenceCanBeSetWithClosure() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let expectation = self.expectation(description: "FlowPersistence closure called") + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self).persistence { + XCTAssertEqual($0, expectedArgs) + defer { expectation.fulfill() } + return .removedAfterProceeding + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let view = try await workflowView.extractWrappedWorkflowItem() + XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) + wait(for: [expectation], timeout: TestConstant.timeout) + } + + func testProceedingWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + } + + func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { .removedAfterProceeding } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteTypeWithDefaultFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + } + + func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + } + + func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToADifferentInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: Int) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { + XCTAssertEqual($0, 1) + return .removedAfterProceeding + } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteTypeArgsWithDefaultFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + } + + func testProceedingWhenInputIsConcreteTypeWithAutoclosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToTheSameInputTypeItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence { _ in .removedAfterProceeding } + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToAnyWorkflowPassedArgsItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: AnyWorkflow.PassedArgs) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testProceedingTwiceWhenInputIsConcreteTypeWithClosureFlowPersistence_WorkflowCanProceedToNeverItem() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnView() async throws { + final class FR0: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + final class FR1: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + final class FR2: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(ViewControllerWrapper.self)) + } +} + +@available(iOS 15, macOS 11, tvOS 14.0, watchOS 7.0, *) +final class ThenProceedOnAppTests: XCTestCase, App { + func testThenProceedFunctionsAsExpectedOnApp() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnApp() async throws { + final class FR0: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + final class FR1: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + final class FR2: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(ViewControllerWrapper.self)) + } +} + +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +final class ThenProceedOnSceneTests: XCTestCase, Scene { + func testThenProceedFunctionsAsExpectedOnScene() async throws { + struct FR0: PassthroughFlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + } + struct FR1: FlowRepresentable, View, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + struct FR2: FlowRepresentable, View, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text(String(describing: Self.self)) } + init(with args: String) { } + } + let expectedArgs = UUID().uuidString + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).persistence(.removedAfterProceeding) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self)) + XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) + } + + func testThenProceedFunctions_WithUIViewControllers_AsExpectedOnScene() async throws { + final class FR0: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + final class FR1: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + final class FR2: UIViewController, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + } + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR0.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try workflowView.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + let wfr1 = try await workflowView.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr1.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(ViewControllerWrapper.self)) + } } From 9c65646bc05e1a05682c9b1237df0b2174b5f849 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 17:14:15 -0700 Subject: [PATCH 12/37] [async-swiftui-tests] - I have a thread sanitizer issue but the latest refactor is still worth it - TT --- .../Views/WorkflowLauncher.swift | 2 +- .../PersistenceTests.swift | 814 +++++++++--------- .../ViewInspector/ViewHostingExtensions.swift | 9 +- .../WorkflowItemExtensions.swift | 20 - 4 files changed, 403 insertions(+), 442 deletions(-) diff --git a/Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift b/Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift index e01b40a95..acb59e2be 100644 --- a/Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift +++ b/Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift @@ -72,7 +72,7 @@ public struct WorkflowLauncher: View { content .environmentObject(model) .environmentObject(launcher) - .onReceive(model.onFinishPublisher, perform: _onFinish) + .onReceive(model.onFinishPublisher.receive(on: DispatchQueue.main), perform: _onFinish) .onReceive(model.onAbandonPublisher) { onAbandon.forEach { $0() } } .onReceive(inspection.notice) { inspection.visit(self, $0) } } diff --git a/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift b/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift index 551aafc00..c017262c6 100644 --- a/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift @@ -1,171 +1,149 @@ -//// -//// PersistenceTests.swift -//// SwiftCurrent_SwiftUI -//// -//// Created by Tyler Thompson on 7/12/21. -//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -//// // -//import XCTest -//import SwiftUI -//import ViewInspector +// PersistenceTests.swift +// SwiftCurrent_SwiftUI // -//import SwiftCurrent -//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work +// Created by Tyler Thompson on 7/12/21. +// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. // -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//final class PersistenceTests: XCTestCase, View { -// override func tearDownWithError() throws { -// removeQueuedExpectations() -// } -// -// // MARK: RemovedAfterProceedingTests -// func testRemovedAfterProceeding_OnFirstItemInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// } -// } -// .persistence(.removedAfterProceeding) -// } -// ).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR2.self).actualView().backUpInWorkflow()) -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testRemovedAfterProceeding_OnMiddleItemInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// } -// .persistence(.removedAfterProceeding) -// } -// } -// ).inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testRemovedAfterProceeding_OnLastItemInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) -// } -// } -// } -// } -// .onFinish { _ in expectOnFinish.fulfill() } -// ).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// XCTAssertThrowsError(try fr4.find(FR4.self)) -// try fr3.actualView().inspect { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self)) -// } -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) -// } + +import XCTest +import SwiftUI +import ViewInspector + +import SwiftCurrent +@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work + +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +final class PersistenceTests: XCTestCase, View { + // MARK: RemovedAfterProceedingTests + func testRemovedAfterProceeding_OnFirstItemInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + } + } + .persistence(.removedAfterProceeding) + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr2.find(FR2.self).actualView().backUpInWorkflow()) + XCTAssertNoThrow(try wfr2.find(FR2.self).actualView().proceedInWorkflow()) + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr3.find(FR3.self).actualView().proceedInWorkflow()) + let wfr4 = try await wfr3.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr4.find(FR4.self).actualView().proceedInWorkflow()) + } + + func testRemovedAfterProceeding_OnMiddleItemInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + } + .persistence(.removedAfterProceeding) + } + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + var wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self).actualView().proceedInWorkflow()) + var wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr3.find(FR3.self).actualView().backUpInWorkflow()) + + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr2.find(FR2.self).actualView().proceedInWorkflow()) + wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr3.find(FR3.self).actualView().proceedInWorkflow()) + let wfr4 = try await wfr3.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr4.find(FR4.self).actualView().proceedInWorkflow()) + } + + func testRemovedAfterProceeding_OnLastItemInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let expectOnFinish = expectation(description: "OnFinish called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self).persistence(.removedAfterProceeding) + } + } + } + } + .onFinish { _ in + expectOnFinish.fulfill() + + } + }.hostAndInspect(with: \.inspection)//.extractWorkflowItem() + + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR4.self).actualView().proceedInWorkflow()) + XCTAssertThrowsError(try launcher.find(FR4.self)) + XCTAssertNoThrow(try launcher.find(FR3.self)) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } // // func testRemovedAfterProceeding_OnMultipleItemsInAWorkflow() throws { // struct FR1: View, FlowRepresentable, Inspectable { @@ -480,258 +458,258 @@ // } // // wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } + + // MARK: PersistWhenSkippedTests +// func testPersistWhenSkipped_OnFirstItemInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// } +// } +// .persistence(.persistWhenSkipped) +// } +// ).inspection.inspect { fr1 in +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().backUpInWorkflow()) +// try fr1.actualView().inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) // } // -// // MARK: PersistWhenSkippedTests -//// func testPersistWhenSkipped_OnFirstItemInAWorkflow() throws { -//// struct FR1: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR1 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// struct FR2: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR2 type") } -//// } -//// struct FR3: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR3 type") } -//// } -//// struct FR4: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR4 type") } -//// } -//// let expectViewLoaded = ViewHosting.loadView( -//// WorkflowLauncher(isLaunched: .constant(true)) { -//// thenProceed(with: FR1.self) { -//// thenProceed(with: FR2.self) { -//// thenProceed(with: FR3.self) { -//// thenProceed(with: FR4.self) -//// } -//// } -//// } -//// .persistence(.persistWhenSkipped) -//// } -//// ).inspection.inspect { fr1 in -//// try fr1.actualView().inspectWrapped { fr2 in -//// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().backUpInWorkflow()) -//// try fr1.actualView().inspect { viewUnderTest in -//// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -//// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -//// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) -//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -//// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) -//// } -//// } -//// } -//// } -//// } -//// } -//// -//// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -//// } -//// -//// func testPersistWhenSkipped_OnMiddleItemInAWorkflow() throws { -//// struct FR1: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR1 type") } -//// } -//// struct FR2: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR2 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// struct FR3: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR3 type") } -//// } -//// struct FR4: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR4 type") } -//// } -//// let expectViewLoaded = ViewHosting.loadView( -//// WorkflowLauncher(isLaunched: .constant(true)) { -//// thenProceed(with: FR1.self) { -//// thenProceed(with: FR2.self) { -//// thenProceed(with: FR3.self) { -//// thenProceed(with: FR4.self) -//// } -//// } -//// .persistence(.persistWhenSkipped) -//// } -//// } -//// ).inspection.inspect { fr1 in -//// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -//// try fr1.actualView().inspectWrapped { fr2 in -//// XCTAssertThrowsError(try fr2.find(FR2.self)) -//// try fr2.actualView().inspectWrapped { fr3 in -//// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) -//// try fr2.actualView().inspect { fr2 in -//// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -//// try fr2.actualView().inspectWrapped { fr3 in -//// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -//// try fr3.actualView().inspectWrapped { fr4 in -//// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -//// } -//// } -//// } -//// } -//// } -//// } -//// -//// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -//// } -//// -//// func testPersistWhenSkipped_OnLastItemInAWorkflow() throws { -//// struct FR1: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR1 type") } -//// } -//// struct FR2: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR2 type") } -//// } -//// struct FR3: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR3 type") } -//// } -//// struct FR4: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR4 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// let expectOnFinish = expectation(description: "OnFinish called") -//// let expectViewLoaded = ViewHosting.loadView( -//// WorkflowLauncher(isLaunched: .constant(true)) { -//// thenProceed(with: FR1.self) { -//// thenProceed(with: FR2.self) { -//// thenProceed(with: FR3.self) { -//// thenProceed(with: FR4.self).persistence(.persistWhenSkipped) -//// } -//// } -//// } -//// } -//// .onFinish { _ in expectOnFinish.fulfill() }) -//// .inspection.inspect { viewUnderTest in -//// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -//// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -//// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -//// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) -//// } -//// } -//// } -//// -//// wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) -//// } -//// -//// func testPersistWhenSkipped_OnMultipleItemsInAWorkflow() throws { -//// struct FR1: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR1 type") } -//// } -//// struct FR2: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR2 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// struct FR3: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR3 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// struct FR4: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR4 type") } -//// } -//// let expectViewLoaded = ViewHosting.loadView( -//// WorkflowLauncher(isLaunched: .constant(true)) { -//// thenProceed(with: FR1.self) { -//// thenProceed(with: FR2.self) { -//// thenProceed(with: FR3.self) { -//// thenProceed(with: FR4.self) -//// } -//// .persistence(.persistWhenSkipped) -//// } -//// .persistence(.persistWhenSkipped) -//// } -//// } -//// ).inspection.inspect { fr1 in -//// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -//// try fr1.actualView().inspectWrapped { fr2 in -//// XCTAssertThrowsError(try fr2.find(FR2.self)) -//// try fr2.actualView().inspectWrapped { fr3 in -//// XCTAssertThrowsError(try fr3.find(FR3.self)) -//// try fr3.actualView().inspectWrapped { fr4 in -//// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().backUpInWorkflow()) -//// try fr3.actualView().inspect { fr3 in -//// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) -//// try fr2.actualView().inspect { fr2 in -//// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -//// try fr2.actualView().inspectWrapped { fr3 in -//// XCTAssertThrowsError(try fr3.find(FR3.self)) -//// try fr3.actualView().inspectWrapped { fr4 in -//// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -//// } -//// } -//// } -//// } -//// } -//// } -//// } -//// } -//// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -//// } -//// -//// func testPersistWhenSkipped_OnAllItemsInAWorkflow() throws { -//// struct FR1: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR1 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// struct FR2: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR2 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// struct FR3: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR3 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// struct FR4: View, FlowRepresentable, Inspectable { -//// var _workflowPointer: AnyFlowRepresentable? -//// var body: some View { Text("FR4 type") } -//// func shouldLoad() -> Bool { false } -//// } -//// let expectOnFinish = expectation(description: "OnFinish called") -//// let expectViewLoaded = ViewHosting.loadView( -//// WorkflowLauncher(isLaunched: .constant(true)) { -//// thenProceed(with: FR1.self) { -//// thenProceed(with: FR2.self) { -//// thenProceed(with: FR3.self) { -//// thenProceed(with: FR4.self).persistence(.persistWhenSkipped) -//// } -//// .persistence(.persistWhenSkipped) -//// } -//// .persistence(.persistWhenSkipped) -//// } -//// .persistence(.persistWhenSkipped) -//// } -//// .onFinish { _ in expectOnFinish.fulfill() }) -//// .inspection.inspect { fr1 in -//// try fr1.actualView().inspectWrapped { fr2 in -//// XCTAssertThrowsError(try fr2.find(FR2.self)) -//// try fr2.actualView().inspectWrapped { fr3 in -//// XCTAssertThrowsError(try fr3.find(FR3.self)) -//// try fr3.actualView().inspectWrapped { fr4 in -//// XCTAssertNoThrow(try fr4.find(FR4.self)) -//// } -//// } -//// } -//// } -//// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -//// } -//} +// func testPersistWhenSkipped_OnMiddleItemInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// } +// .persistence(.persistWhenSkipped) +// } +// } +// ).inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertThrowsError(try fr2.find(FR2.self)) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) +// try fr2.actualView().inspect { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// } +// } +// +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testPersistWhenSkipped_OnLastItemInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// func shouldLoad() -> Bool { false } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self).persistence(.persistWhenSkipped) +// } +// } +// } +// } +// .onFinish { _ in expectOnFinish.fulfill() }) +// .inspection.inspect { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) +// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in +// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) +// } +// } +// } +// +// wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) +// } +// +// func testPersistWhenSkipped_OnMultipleItemsInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// } +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self) +// } +// .persistence(.persistWhenSkipped) +// } +// .persistence(.persistWhenSkipped) +// } +// } +// ).inspection.inspect { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertThrowsError(try fr2.find(FR2.self)) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertThrowsError(try fr3.find(FR3.self)) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().backUpInWorkflow()) +// try fr3.actualView().inspect { fr3 in +// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) +// try fr2.actualView().inspect { fr2 in +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertThrowsError(try fr3.find(FR3.self)) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// } +// } +// } +// } +// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) +// } +// +// func testPersistWhenSkipped_OnAllItemsInAWorkflow() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR3: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR3 type") } +// func shouldLoad() -> Bool { false } +// } +// struct FR4: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR4 type") } +// func shouldLoad() -> Bool { false } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self) { +// thenProceed(with: FR3.self) { +// thenProceed(with: FR4.self).persistence(.persistWhenSkipped) +// } +// .persistence(.persistWhenSkipped) +// } +// .persistence(.persistWhenSkipped) +// } +// .persistence(.persistWhenSkipped) +// } +// .onFinish { _ in expectOnFinish.fulfill() }) +// .inspection.inspect { fr1 in +// try fr1.actualView().inspectWrapped { fr2 in +// XCTAssertThrowsError(try fr2.find(FR2.self)) +// try fr2.actualView().inspectWrapped { fr3 in +// XCTAssertThrowsError(try fr3.find(FR3.self)) +// try fr3.actualView().inspectWrapped { fr4 in +// XCTAssertNoThrow(try fr4.find(FR4.self)) +// } +// } +// } +// } +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } +} diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index ce642839d..71886c9de 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -14,9 +14,12 @@ import XCTest @available(iOS 15.0, macOS 10.15, tvOS 13.0, *) extension View where Self: Inspectable { - func hostAndInspect(with emmisary: KeyPath) async throws -> InspectableView> where E.V == Self { - DispatchQueue.main.async { ViewHosting.host(view: self) } - return try await self[keyPath: emmisary].inspect() + func host() async { + await MainActor.run { ViewHosting.host(view: self ) } + } + func hostAndInspect(with emissary: KeyPath) async throws -> InspectableView> where E.V == Self { + await host() + return try await self[keyPath: emissary].inspect() } } diff --git a/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift index ac6ffff93..e8dc7339b 100644 --- a/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/WorkflowItemExtensions.swift @@ -17,24 +17,4 @@ extension WorkflowItem { func getWrappedView() throws -> Wrapped { try XCTUnwrap((Mirror(reflecting: self).descendant("_wrapped") as? State)?.wrappedValue) } - -// @discardableResult func inspectWrapped(function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation where Wrapped == WorkflowItem { -// let wrapped = try XCTUnwrap((Mirror(reflecting: self).descendant("_wrapped") as? State)?.wrappedValue) -// return try wrapped.inspect(function: function, file: file, line: line, inspection: inspection) -// } -// -// @discardableResult func inspect(function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation { -// // Waiting for 0.0 seems insane but think about it like "We are waiting for this command to get off the stack" -// // Then quit thinking about it, know it was deliberate, and move on. -// let expectation = self.inspection.inspect(after: 0, function: function, file: file, line: line) { -// try inspection($0) -// } -// XCTestCase.queuedExpectations.append(expectation) -// return expectation -// } -// -// @discardableResult func inspect(model: WorkflowViewModel, launcher: Launcher, function: String = #function, file: StaticString = #file, line: UInt = #line, inspection: @escaping (InspectableView>) throws -> Void) throws -> XCTestExpectation { -// try ViewHosting.loadView(self, model: model, launcher: launcher).inspect(function: function, file: file, line: line, inspection: inspection) -// } - } From 8515382dceb14c841f28c978c98dd425632c98f5 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 17:45:53 -0700 Subject: [PATCH 13/37] [async-swiftui-tests] - Thread sanitizer issues resolved, this is turning out really nice - TT --- .../GenericConstraintTests.swift | 220 +++---- .../PersistenceTests.swift | 616 ++++++++---------- .../ViewInspector/ViewHostingExtensions.swift | 27 + 3 files changed, 409 insertions(+), 454 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 372af1637..7b5e7ee7e 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -143,7 +143,7 @@ final class GenericConstraintTests: XCTestCase, View { } } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.actualView().getWrappedView() XCTAssertNoThrow(try workflowView.find(type(of: view)).find(FR2.self)) } @@ -166,7 +166,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -189,7 +189,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -212,7 +212,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -236,7 +236,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -260,7 +260,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -284,7 +284,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -309,7 +309,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -334,7 +334,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -418,7 +418,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -444,7 +444,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -473,7 +473,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -499,7 +499,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -526,7 +526,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -556,7 +556,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -583,7 +583,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -611,7 +611,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -642,7 +642,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -725,7 +725,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -751,7 +751,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -780,7 +780,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -806,7 +806,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -833,7 +833,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -863,7 +863,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR1.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -890,7 +890,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -918,7 +918,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -949,7 +949,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowView.find(FR1.self).proceedInWorkflow(1) let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -976,7 +976,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow("")) + try await workflowView.find(FR1.self).proceedInWorkflow("") let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -1004,7 +1004,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow("")) + try await workflowView.find(FR1.self).proceedInWorkflow("") let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -1035,7 +1035,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try workflowView.find(FR1.self).actualView().proceedInWorkflow("")) + try await workflowView.find(FR1.self).proceedInWorkflow("") let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -1063,7 +1063,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) } @@ -1091,7 +1091,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) wait(for: [expectation], timeout: TestConstant.timeout) @@ -1122,11 +1122,11 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) @@ -1157,9 +1157,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1190,9 +1190,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1224,9 +1224,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -1257,9 +1257,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1291,9 +1291,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) @@ -1327,9 +1327,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowItem.find(FR1.self).proceedInWorkflow(1) let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -1361,9 +1361,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowItem.find(FR1.self).proceedInWorkflow(1) let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1399,9 +1399,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow(1)) + try await workflowItem.find(FR1.self).proceedInWorkflow(1) let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1430,7 +1430,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) } @@ -1460,7 +1460,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) wait(for: [expectation], timeout: TestConstant.timeout) @@ -1492,9 +1492,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) } @@ -1525,9 +1525,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try workflowItem.find(FR1.self).actualView().proceedInWorkflow()) + try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem() XCTAssertNoThrow(try view.find(FR2.self)) XCTAssertEqual(try view.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1562,10 +1562,10 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() XCTAssertEqual(try wfr1.find(FR1.self).actualView().persistence, .removedAfterProceeding) - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) } @@ -1597,9 +1597,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) } @@ -1631,9 +1631,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1669,9 +1669,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1705,9 +1705,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + try await wfr1.find(FR1.self).proceedInWorkflow(1) let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) } @@ -1740,9 +1740,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + try await wfr1.find(FR1.self).proceedInWorkflow(1) let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1779,9 +1779,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + try await wfr1.find(FR1.self).proceedInWorkflow(1) let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1829,7 +1829,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) } @@ -1859,7 +1859,7 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let view = try await workflowView.extractWrappedWorkflowItem() XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) wait(for: [expectation], timeout: TestConstant.timeout) @@ -1891,9 +1891,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) } @@ -1924,9 +1924,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1958,9 +1958,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -1993,9 +1993,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) } @@ -2027,9 +2027,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2062,9 +2062,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2098,9 +2098,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + try await wfr1.find(FR1.self).proceedInWorkflow(1) let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) } @@ -2133,9 +2133,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + try await wfr1.find(FR1.self).proceedInWorkflow(1) let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2172,9 +2172,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(1)) + try await wfr1.find(FR1.self).proceedInWorkflow(1) let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2208,9 +2208,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + try await wfr1.find(FR1.self).proceedInWorkflow("") let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) } @@ -2243,9 +2243,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + try await wfr1.find(FR1.self).proceedInWorkflow("") let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2279,9 +2279,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + try await wfr1.find(FR1.self).proceedInWorkflow("") let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2315,9 +2315,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) + try await wfr1.find(FR1.self).proceedInWorkflow(expectedArgs) let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2350,9 +2350,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow(expectedArgs)) + try await wfr1.find(FR1.self).proceedInWorkflow(expectedArgs) let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2381,9 +2381,9 @@ final class GenericConstraintTests: XCTestCase, View { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + try await workflowView.find(ViewControllerWrapper.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + try await wfr1.find(ViewControllerWrapper.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(ViewControllerWrapper.self)) } @@ -2419,9 +2419,9 @@ final class ThenProceedOnAppTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + try await wfr1.find(FR1.self).proceedInWorkflow("") let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2450,9 +2450,9 @@ final class ThenProceedOnAppTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + try await workflowView.find(ViewControllerWrapper.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + try await wfr1.find(ViewControllerWrapper.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(ViewControllerWrapper.self)) } @@ -2488,9 +2488,9 @@ final class ThenProceedOnSceneTests: XCTestCase, Scene { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(FR0.self).actualView().proceedInWorkflow()) + try await workflowView.find(FR0.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow("")) + try await wfr1.find(FR1.self).proceedInWorkflow("") let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(FR2.self)) XCTAssertEqual(try wfr2.find(FR2.self).actualView().persistence, .removedAfterProceeding) @@ -2519,9 +2519,9 @@ final class ThenProceedOnSceneTests: XCTestCase, Scene { } }.hostAndInspect(with: \.inspection).extractWorkflowItem() - XCTAssertNoThrow(try workflowView.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + try await workflowView.find(ViewControllerWrapper.self).proceedInWorkflow() let wfr1 = try await workflowView.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr1.find(ViewControllerWrapper.self).actualView().proceedInWorkflow()) + try await wfr1.find(ViewControllerWrapper.self).proceedInWorkflow() let wfr2 = try await wfr1.extractWrappedWorkflowItem() XCTAssertNoThrow(try wfr2.find(ViewControllerWrapper.self)) } diff --git a/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift b/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift index c017262c6..431647f32 100644 --- a/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift @@ -33,7 +33,7 @@ final class PersistenceTests: XCTestCase, View { var _workflowPointer: AnyFlowRepresentable? var body: some View { Text("FR4 type") } } - let wfr1 = try await MainActor.run { + let launcher = try await MainActor.run { WorkflowLauncher(isLaunched: .constant(true)) { thenProceed(with: FR1.self) { thenProceed(with: FR2.self) { @@ -44,16 +44,13 @@ final class PersistenceTests: XCTestCase, View { } .persistence(.removedAfterProceeding) } - }.hostAndInspect(with: \.inspection).extractWorkflowItem() + }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) - let wfr2 = try await wfr1.extractWrappedWorkflowItem() - XCTAssertThrowsError(try wfr2.find(FR2.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try wfr2.find(FR2.self).actualView().proceedInWorkflow()) - let wfr3 = try await wfr2.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr3.find(FR3.self).actualView().proceedInWorkflow()) - let wfr4 = try await wfr3.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr4.find(FR4.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR2.self).actualView().backUpInWorkflow()) + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR4.self).proceedInWorkflow() } func testRemovedAfterProceeding_OnMiddleItemInAWorkflow() async throws { @@ -73,7 +70,7 @@ final class PersistenceTests: XCTestCase, View { var _workflowPointer: AnyFlowRepresentable? var body: some View { Text("FR4 type") } } - let wfr1 = try await MainActor.run { + let launcher = try await MainActor.run { WorkflowLauncher(isLaunched: .constant(true)) { thenProceed(with: FR1.self) { thenProceed(with: FR2.self) { @@ -84,21 +81,16 @@ final class PersistenceTests: XCTestCase, View { .persistence(.removedAfterProceeding) } } - }.hostAndInspect(with: \.inspection).extractWorkflowItem() + }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) - var wfr2 = try await wfr1.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr2.find(FR2.self).actualView().proceedInWorkflow()) - var wfr3 = try await wfr2.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr3.find(FR3.self).actualView().backUpInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + XCTAssertNoThrow(try launcher.find(FR3.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) - wfr2 = try await wfr1.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr2.find(FR2.self).actualView().proceedInWorkflow()) - wfr3 = try await wfr2.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr3.find(FR3.self).actualView().proceedInWorkflow()) - let wfr4 = try await wfr3.extractWrappedWorkflowItem() - XCTAssertNoThrow(try wfr4.find(FR4.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR4.self).proceedInWorkflow() } func testRemovedAfterProceeding_OnLastItemInAWorkflow() async throws { @@ -133,332 +125,268 @@ final class PersistenceTests: XCTestCase, View { expectOnFinish.fulfill() } - }.hostAndInspect(with: \.inspection)//.extractWorkflowItem() + }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR4.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR4.self).proceedInWorkflow() XCTAssertThrowsError(try launcher.find(FR4.self)) XCTAssertNoThrow(try launcher.find(FR3.self)) wait(for: [expectOnFinish], timeout: TestConstant.timeout) } -// -// func testRemovedAfterProceeding_OnMultipleItemsInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// } -// ).inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().backUpInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testRemovedAfterProceeding_OnAllItemsInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let binding = Binding(wrappedValue: true) -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: binding) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .onFinish { _ in expectOnFinish.fulfill() }) -// .inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// XCTAssertThrowsError(try fr4.find(FR4.self)) -// try fr3.actualView().inspect { fr3 in -// XCTAssertThrowsError(try fr3.find(FR3.self)) -// try fr2.actualView().inspect { fr2 in -// XCTAssertThrowsError(try fr2.find(FR2.self)) -// try fr1.actualView().inspect { fr1 in -// XCTAssertThrowsError(try fr1.find(FR1.self)) -// XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") -// } -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// // MARK: Closure API Tests -// -// func testPersistenceWorks_WhenDefinedFromAClosure() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// init(with args: String) { } -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let binding = Binding(wrappedValue: true) -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectedStart = UUID().uuidString -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: binding, startingArgs: expectedStart) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence { -// XCTAssertEqual($0, expectedStart) -// return .removedAfterProceeding -// } -// } -// .onFinish { _ in expectOnFinish.fulfill() }) -// .inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// XCTAssertThrowsError(try fr4.find(FR4.self)) -// try fr3.actualView().inspect { fr3 in -// XCTAssertThrowsError(try fr3.find(FR3.self)) -// try fr2.actualView().inspect { fr2 in -// XCTAssertThrowsError(try fr2.find(FR2.self)) -// try fr1.actualView().inspect { fr1 in -// XCTAssertThrowsError(try fr1.find(FR1.self)) -// XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") -// } -// } -// } -// } -// } -// } -// } -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testPersistenceWorks_WhenDefinedFromAClosure_AndItemHasInputOfPassedArgs() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// init(with args: AnyWorkflow.PassedArgs) { } -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let binding = Binding(wrappedValue: true) -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectedStart = AnyWorkflow.PassedArgs.args(UUID().uuidString) -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: binding, startingArgs: expectedStart) { -// thenProceed(with: FR1.self) { -// -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence { -// XCTAssertNotNil(expectedStart.extractArgs(defaultValue: 1) as? String) -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedStart.extractArgs(defaultValue: 1) as? String) -// return .removedAfterProceeding -// } -// } -// .onFinish { _ in expectOnFinish.fulfill() }) -// .inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// XCTAssertThrowsError(try fr4.find(FR4.self)) -// try fr3.actualView().inspect { fr3 in -// XCTAssertThrowsError(try fr3.find(FR3.self)) -// try fr2.actualView().inspect { fr2 in -// XCTAssertThrowsError(try fr2.find(FR2.self)) -// try fr1.actualView().inspect { fr1 in -// XCTAssertThrowsError(try fr1.find(FR1.self)) -// XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") -// } -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testPersistenceWorks_WhenDefinedFromAClosure_AndItemHasInputOfNever() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let binding = Binding(wrappedValue: true) -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: binding) { -// thenProceed(with: FR1.self) { -// -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self).persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence(.removedAfterProceeding) -// } -// .persistence { .removedAfterProceeding } -// } -// .onFinish { _ in expectOnFinish.fulfill() }) -// .inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertThrowsError(try fr4.find(FR4.self).actualView().backUpInWorkflow()) -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// XCTAssertThrowsError(try fr4.find(FR4.self)) -// try fr3.actualView().inspect { fr3 in -// XCTAssertThrowsError(try fr3.find(FR3.self)) -// try fr2.actualView().inspect { fr2 in -// XCTAssertThrowsError(try fr2.find(FR2.self)) -// try fr1.actualView().inspect { fr1 in -// XCTAssertThrowsError(try fr1.find(FR1.self)) -// XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") -// } -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } + + func testRemovedAfterProceeding_OnMultipleItemsInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + .persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + XCTAssertNoThrow(try launcher.find(FR4.self).actualView().backUpInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR4.self).proceedInWorkflow() + } + + func testRemovedAfterProceeding_OnAllItemsInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let binding = Binding(wrappedValue: true) + let expectOnFinish = expectation(description: "OnFinish called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: binding) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self).persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .onFinish { _ in expectOnFinish.fulfill() } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self).actualView().backUpInWorkflow()) + try await launcher.find(FR4.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self)) + XCTAssertThrowsError(try launcher.find(FR3.self)) + XCTAssertThrowsError(try launcher.find(FR2.self)) + XCTAssertThrowsError(try launcher.find(FR1.self)) + XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + // MARK: Closure API Tests + + func testPersistenceWorks_WhenDefinedFromAClosure() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + init(with args: String) { } + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let binding = Binding(wrappedValue: true) + let expectOnFinish = expectation(description: "OnFinish called") + let expectedStart = UUID().uuidString + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: binding, startingArgs: expectedStart) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self).persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .persistence { + XCTAssertEqual($0, expectedStart) + return .removedAfterProceeding + } + } + .onFinish { _ in expectOnFinish.fulfill() } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self).actualView().backUpInWorkflow()) + try await launcher.find(FR4.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self)) + XCTAssertThrowsError(try launcher.find(FR3.self)) + XCTAssertThrowsError(try launcher.find(FR2.self)) + XCTAssertThrowsError(try launcher.find(FR1.self)) + XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testPersistenceWorks_WhenDefinedFromAClosure_AndItemHasInputOfPassedArgs() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + init(with args: AnyWorkflow.PassedArgs) { } + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let binding = Binding(wrappedValue: true) + let expectOnFinish = expectation(description: "OnFinish called") + let expectedStart = AnyWorkflow.PassedArgs.args(UUID().uuidString) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: binding, startingArgs: expectedStart) { + thenProceed(with: FR1.self) { + + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self).persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .persistence { + XCTAssertNotNil(expectedStart.extractArgs(defaultValue: 1) as? String) + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedStart.extractArgs(defaultValue: 1) as? String) + return .removedAfterProceeding + } + } + .onFinish { _ in expectOnFinish.fulfill() } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self).actualView().backUpInWorkflow()) + try await launcher.find(FR4.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self)) + XCTAssertThrowsError(try launcher.find(FR3.self)) + XCTAssertThrowsError(try launcher.find(FR2.self)) + XCTAssertThrowsError(try launcher.find(FR1.self)) + XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testPersistenceWorks_WhenDefinedFromAClosure_AndItemHasInputOfNever() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let binding = Binding(wrappedValue: true) + let expectOnFinish = expectation(description: "OnFinish called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: binding) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self).persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .persistence(.removedAfterProceeding) + } + .persistence { .removedAfterProceeding } + } + .onFinish { _ in expectOnFinish.fulfill() } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self).actualView().backUpInWorkflow()) + try await launcher.find(FR4.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self)) + XCTAssertThrowsError(try launcher.find(FR3.self)) + XCTAssertThrowsError(try launcher.find(FR2.self)) + XCTAssertThrowsError(try launcher.find(FR1.self)) + XCTAssertFalse(binding.wrappedValue, "Binding should be flipped to false") + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } // MARK: PersistWhenSkippedTests // func testPersistWhenSkipped_OnFirstItemInAWorkflow() throws { diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index 71886c9de..dec8c33ba 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -9,6 +9,7 @@ import Foundation import SwiftUI import ViewInspector import XCTest +import SwiftCurrent @testable import SwiftCurrent_SwiftUI @@ -54,6 +55,32 @@ extension InspectableView where View: CustomViewType & SingleViewContent { } } +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +extension InspectableView where View: CustomViewType & SingleViewContent, View.T: FlowRepresentable { + func proceedInWorkflow() async throws where View.T.WorkflowOutput == Never { + try await MainActor.run { try actualView().proceedInWorkflow() } + } + + func proceedInWorkflow(_ args: View.T.WorkflowOutput) async throws where View.T.WorkflowOutput == AnyWorkflow.PassedArgs { + try await MainActor.run { try actualView().proceedInWorkflow(args) } + } + + func proceedInWorkflow(_ args: View.T.WorkflowOutput) async throws { + try await MainActor.run { try actualView().proceedInWorkflow(args) } + } + + func backUpInWorkflow() async throws { + try await MainActor.run { try actualView().backUpInWorkflow() } + } +} + +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +extension InspectableView where View: CustomViewType & SingleViewContent, View.T: PassthroughFlowRepresentable { + func proceedInWorkflow() async throws { + try await MainActor.run { try actualView().proceedInWorkflow() } + } +} + @available(iOS 15.0, macOS 10.15, tvOS 13.0, *) public extension InspectionEmissary where V: View & Inspectable { func inspect(after delay: TimeInterval = 0, From f83a5454ed5ad4a2dfa17ddd7f9cce0d68a6b3e8 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 17:52:32 -0700 Subject: [PATCH 14/37] [async-swiftui-tests] - Another set of tests refactored - TT --- .../SwiftCurrent_SwiftUITests/SkipTests.swift | 454 ++++++++---------- 1 file changed, 208 insertions(+), 246 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SkipTests.swift b/Tests/SwiftCurrent_SwiftUITests/SkipTests.swift index 105137664..d20bd15e4 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SkipTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SkipTests.swift @@ -1,249 +1,211 @@ -//// -//// SkipTests.swift -//// SwiftCurrent -//// -//// Created by Tyler Thompson on 7/12/21. -//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -//// // -//import XCTest -//import SwiftUI -//import ViewInspector +// SkipTests.swift +// SwiftCurrent // -//import SwiftCurrent -//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work +// Created by Tyler Thompson on 7/12/21. +// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. // -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//final class SkipTests: XCTestCase, View { -// override func tearDownWithError() throws { -// removeQueuedExpectations() -// } -// -// func testSkippingFirstItemInAWorkflow() throws { -// // NOTE: Workflows in the past had issues with 4+ items, so this is to cover our bases. SwiftUI also has a nasty habit of behaving a little differently as number of views increase. -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// } -// } -// } -// ).inspection.inspect { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testSkippingMiddleItemInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// } -// } -// } -// ).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testSkippingLastItemInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// func shouldLoad() -> Bool { false } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// } -// } -// } -// .onFinish { _ in expectOnFinish.fulfill() }) -// .inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// XCTAssertThrowsError(try fr3.find(FR4.self)) -// XCTAssertNoThrow(try fr3.find(FR3.self)) -// } -// } -// } -// -// wait(for: [expectViewLoaded, expectOnFinish], timeout: TestConstant.timeout) -// } -// -// func testSkippingMultipleItemsInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// } -// } -// } -// ).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR2.self).actualView()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR3.self).actualView()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testSkippingAllItemsInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// func shouldLoad() -> Bool { false } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// } -// } -// } -// .onFinish { _ in expectOnFinish.fulfill() }) -// .inspection.inspect { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR3.self)) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertThrowsError(try viewUnderTest.find(FR4.self)) -// } -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -//} + +import XCTest +import SwiftUI +import ViewInspector + +import SwiftCurrent +@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work + +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +final class SkipTests: XCTestCase, View { + func testSkippingFirstItemInAWorkflow() async throws { + // NOTE: Workflows in the past had issues with 4+ items, so this is to cover our bases. SwiftUI also has a nasty habit of behaving a little differently as number of views increase. + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + func shouldLoad() -> Bool { false } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + } + } + } + }.hostAndInspect(with: \.inspection) + + XCTAssertThrowsError(try launcher.find(FR1.self)) + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR4.self).proceedInWorkflow() + } + + func testSkippingMiddleItemInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + func shouldLoad() -> Bool { false } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + } + } + } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR2.self)) + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR4.self).proceedInWorkflow() + } + + func testSkippingLastItemInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + func shouldLoad() -> Bool { false } + } + let expectOnFinish = expectation(description: "OnFinish called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + } + } + } + .onFinish { _ in expectOnFinish.fulfill() } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR4.self)) + XCTAssertNoThrow(try launcher.find(FR3.self)) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testSkippingMultipleItemsInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + func shouldLoad() -> Bool { false } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + func shouldLoad() -> Bool { false } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + } + } + } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).proceedInWorkflow() + XCTAssertThrowsError(try launcher.find(FR2.self).actualView()) + XCTAssertThrowsError(try launcher.find(FR3.self).actualView()) + try await launcher.find(FR4.self).proceedInWorkflow() + } + + func testSkippingAllItemsInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + func shouldLoad() -> Bool { false } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + func shouldLoad() -> Bool { false } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + func shouldLoad() -> Bool { false } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + func shouldLoad() -> Bool { false } + } + let expectOnFinish = expectation(description: "OnFinish called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + } + } + } + .onFinish { _ in expectOnFinish.fulfill() } + }.hostAndInspect(with: \.inspection) + + XCTAssertThrowsError(try launcher.find(FR1.self)) + XCTAssertThrowsError(try launcher.find(FR2.self)) + XCTAssertThrowsError(try launcher.find(FR3.self)) + XCTAssertThrowsError(try launcher.find(FR4.self)) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } +} From 2441c03a66b106347153e7490b91aab0a5d81d5d Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 18:27:36 -0700 Subject: [PATCH 15/37] [async-swiftui-tests] - Finally cracked the modal thing...that was trickier than I expected - TT --- .../SwiftCurrent_ModalTests.swift | 154 ++++++++---------- .../ViewInspector/ViewHostingExtensions.swift | 5 + 2 files changed, 77 insertions(+), 82 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift index 73097c849..8be5dfdc0 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift @@ -1,69 +1,59 @@ -//// -//// SwiftCurrent_ModalTests.swift -//// SwiftCurrent -//// -//// Created by Tyler Thompson on 7/12/21. -//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -//// -// -//import XCTest -//import SwiftUI -// -//import SwiftCurrent -// -//@testable import ViewInspector -//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//extension InspectableView where View == ViewType.Sheet { -// func isPresented() throws -> Bool { -// return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false -// } -//} -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//final class SwiftCurrent_ModalTests: XCTestCase, Scene { -// override func tearDownWithError() throws { -// removeQueuedExpectations() -// } -// -// func testWorkflowCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).presentationType(.modal) -// } -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertEqual(try fr1.find(FR1.self).text().string(), "FR1 type") -// try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in -// XCTAssertTrue(try fr1.find(ViewType.Sheet.self).isPresented()) -// try fr1.find(ViewType.Sheet.self).find(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssertEqual(try fr2.view(FR2.self).text().string(), "FR2 type") -// XCTAssertNoThrow(try fr2.view(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } // +// SwiftCurrent_ModalTests.swift +// SwiftCurrent +// +// Created by Tyler Thompson on 7/12/21. +// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +// + +import XCTest +import SwiftUI + +import SwiftCurrent + +@testable import ViewInspector +@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work + +@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +extension InspectableView where View == ViewType.Sheet { + func isPresented() throws -> Bool { + return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false + } +} + +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +final class SwiftCurrent_ModalTests: XCTestCase, Scene { + func testWorkflowCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + let expectOnFinish = expectation(description: "OnFinish called") + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).presentationType(.modal) + } + } + .onFinish { _ in + expectOnFinish.fulfill() + } + }.hostAndInspect(with: \.inspection).extractWorkflowItem() + + let fr1 = try wfr1.find(FR1.self) + XCTAssertEqual(try fr1.text().string(), "FR1 type") + try await fr1.proceedInWorkflow() + let fr2 = try fr1.find(ViewType.Sheet.self).find(FR2.self) + XCTAssertEqual(try fr2.text().string(), "FR2 type") + try await fr2.proceedInWorkflow() + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + // func testWorkflowItemsOfTheSameTypeCanBeFollowed() throws { // struct FR1: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? @@ -81,17 +71,17 @@ // ).inspection.inspect { fr1 in // let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try await fr1.find(FR1.self).proceedInWorkflow() // try fr1.actualView().inspect { first in // XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) // try first.find(ViewType.Sheet.self).view(WorkflowItem, FR1>.self).actualView().inspect(model: model, launcher: launcher) { second in // XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) -// XCTAssertNoThrow(try second.find(FR1.self).actualView().proceedInWorkflow()) +// try await second.find(FR1.self).proceedInWorkflow() // try second.actualView().inspect { second in // XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) // try second.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { third in -// XCTAssertNoThrow(try third.find(FR1.self).actualView().proceedInWorkflow()) +// try await third.find(FR1.self).proceedInWorkflow() // try third.actualView().inspect { third in // XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) @@ -162,7 +152,7 @@ // ).inspection.inspect { fr_1 in // model = (Mirror(reflecting: try fr_1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // launcher = (Mirror(reflecting: try fr_1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr_1.find(FR1.self).actualView().proceedInWorkflow()) +// try await fr_1.find(FR1.self).proceedInWorkflow() // try fr_1.actualView().inspect { fr_1 in // XCTAssert(try fr_1.find(ViewType.Sheet.self).isPresented()) // fr1 = fr_1 @@ -175,7 +165,7 @@ // // try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr_2 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssertNoThrow(try fr_2.find(FR2.self).actualView().proceedInWorkflow()) +// try await fr_2.find(FR2.self).proceedInWorkflow() // try fr_2.actualView().inspect { fr_2 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr_2.find(ViewType.Sheet.self).isPresented()) @@ -186,7 +176,7 @@ // removeQueuedExpectations() // // try fr2.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>.self).actualView().inspect(model: model, launcher: launcher) { fr_3 in -// XCTAssertNoThrow(try fr_3.find(FR3.self).actualView().proceedInWorkflow()) +// try await fr_3.find(FR3.self).proceedInWorkflow() // try fr_3.actualView().inspect { fr_3 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -198,7 +188,7 @@ // removeQueuedExpectations() // // try fr3.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>.self).actualView().inspect(model: model, launcher: launcher) { fr_4 in -// XCTAssertNoThrow(try fr_4.find(FR4.self).actualView().proceedInWorkflow()) +// try await fr_4.find(FR4.self).proceedInWorkflow() // try fr_4.actualView().inspect { fr_4 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -211,7 +201,7 @@ // removeQueuedExpectations() // // try fr4.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>.self).actualView().inspect(model: model, launcher: launcher) { fr_5 in -// XCTAssertNoThrow(try fr_5.find(FR5.self).actualView().proceedInWorkflow()) +// try await fr_5.find(FR5.self).proceedInWorkflow() // try fr_5.actualView().inspect { fr_5 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -225,7 +215,7 @@ // removeQueuedExpectations() // // try fr5.find(ViewType.Sheet.self).view(WorkflowItem, FR6>.self).actualView().inspect(model: model, launcher: launcher) { fr_6 in -// XCTAssertNoThrow(try fr_6.find(FR6.self).actualView().proceedInWorkflow()) +// try await fr_6.find(FR6.self).proceedInWorkflow() // try fr_6.actualView().inspect { fr_6 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -240,7 +230,7 @@ // removeQueuedExpectations() // // try fr6.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr7 in -// XCTAssertNoThrow(try fr7.find(FR7.self).actualView().proceedInWorkflow()) +// try await fr7.find(FR7.self).proceedInWorkflow() // try fr7.actualView().inspect { fr7 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -279,7 +269,7 @@ // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue // XCTAssertThrowsError(try fr1.find(FR1.self).actualView()) // try fr1.view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try await fr2.find(FR2.self).proceedInWorkflow() // try fr2.actualView().inspect { fr2 in // try fr2.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -317,7 +307,7 @@ // ).inspection.inspect { fr1 in // let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try await fr1.find(FR1.self).proceedInWorkflow() // try fr1.actualView().inspect { fr1 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in @@ -363,7 +353,7 @@ // ).inspection.inspect { fr1 in // let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try await fr1.find(FR1.self).proceedInWorkflow() // try fr1.actualView().inspect { fr1 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR3>, FR2>.self).view(WorkflowItem, FR3>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr4 in @@ -407,17 +397,17 @@ // }).inspection.inspect { fr1 in // let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try await fr1.find(FR1.self).proceedInWorkflow() // try fr1.actualView().inspect { fr1 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) +// try await fr2.find(FR2.self).proceedInWorkflow() // } // } // } // // wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) // } -// -//} + +} diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index dec8c33ba..ae7ff0bda 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -18,6 +18,11 @@ extension View where Self: Inspectable { func host() async { await MainActor.run { ViewHosting.host(view: self ) } } + + func host(_ transform: (Self) -> V) async { + await MainActor.run { ViewHosting.host(view: transform(self) ) } + } + func hostAndInspect(with emissary: KeyPath) async throws -> InspectableView> where E.V == Self { await host() return try await self[keyPath: emissary].inspect() From 8efd308dfb03bd9e0282b1e5a512e60a8646b5bb Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Fri, 4 Feb 2022 19:25:45 -0700 Subject: [PATCH 16/37] [async-swiftui-tests] - Modal tests had an intermittent failure, reset them for now - TT --- .../Views/WorkflowLauncher.swift | 2 +- .../SwiftCurrent_ModalTests.swift | 154 ++++++++++-------- 2 files changed, 83 insertions(+), 73 deletions(-) diff --git a/Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift b/Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift index acb59e2be..e01b40a95 100644 --- a/Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift +++ b/Sources/SwiftCurrent_SwiftUI/Views/WorkflowLauncher.swift @@ -72,7 +72,7 @@ public struct WorkflowLauncher: View { content .environmentObject(model) .environmentObject(launcher) - .onReceive(model.onFinishPublisher.receive(on: DispatchQueue.main), perform: _onFinish) + .onReceive(model.onFinishPublisher, perform: _onFinish) .onReceive(model.onAbandonPublisher) { onAbandon.forEach { $0() } } .onReceive(inspection.notice) { inspection.visit(self, $0) } } diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift index 8be5dfdc0..73097c849 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift @@ -1,59 +1,69 @@ +//// +//// SwiftCurrent_ModalTests.swift +//// SwiftCurrent +//// +//// Created by Tyler Thompson on 7/12/21. +//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +//// +// +//import XCTest +//import SwiftUI +// +//import SwiftCurrent +// +//@testable import ViewInspector +//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//extension InspectableView where View == ViewType.Sheet { +// func isPresented() throws -> Bool { +// return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false +// } +//} +// +//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +//final class SwiftCurrent_ModalTests: XCTestCase, Scene { +// override func tearDownWithError() throws { +// removeQueuedExpectations() +// } +// +// func testWorkflowCanBeFollowed() throws { +// struct FR1: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR1 type") } +// } +// struct FR2: View, FlowRepresentable, Inspectable { +// var _workflowPointer: AnyFlowRepresentable? +// var body: some View { Text("FR2 type") } +// } +// let expectOnFinish = expectation(description: "OnFinish called") +// let expectViewLoaded = ViewHosting.loadView( +// WorkflowLauncher(isLaunched: .constant(true)) { +// thenProceed(with: FR1.self) { +// thenProceed(with: FR2.self).presentationType(.modal) +// } +// } +// .onFinish { _ in +// expectOnFinish.fulfill() +// }).inspection.inspect { fr1 in +// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue +// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue +// XCTAssertEqual(try fr1.find(FR1.self).text().string(), "FR1 type") +// try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) +// try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in +// XCTAssertTrue(try fr1.find(ViewType.Sheet.self).isPresented()) +// try fr1.find(ViewType.Sheet.self).find(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr2 in +// XCTAssertEqual(try fr2.view(FR2.self).text().string(), "FR2 type") +// XCTAssertNoThrow(try fr2.view(FR2.self).actualView().proceedInWorkflow()) +// } +// } +// } +// } +// +// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) +// } // -// SwiftCurrent_ModalTests.swift -// SwiftCurrent -// -// Created by Tyler Thompson on 7/12/21. -// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -// - -import XCTest -import SwiftUI - -import SwiftCurrent - -@testable import ViewInspector -@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -extension InspectableView where View == ViewType.Sheet { - func isPresented() throws -> Bool { - return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false - } -} - -@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -final class SwiftCurrent_ModalTests: XCTestCase, Scene { - func testWorkflowCanBeFollowed() async throws { - struct FR1: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR1 type") } - } - struct FR2: View, FlowRepresentable, Inspectable { - var _workflowPointer: AnyFlowRepresentable? - var body: some View { Text("FR2 type") } - } - let expectOnFinish = expectation(description: "OnFinish called") - let wfr1 = try await MainActor.run { - WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self).presentationType(.modal) - } - } - .onFinish { _ in - expectOnFinish.fulfill() - } - }.hostAndInspect(with: \.inspection).extractWorkflowItem() - - let fr1 = try wfr1.find(FR1.self) - XCTAssertEqual(try fr1.text().string(), "FR1 type") - try await fr1.proceedInWorkflow() - let fr2 = try fr1.find(ViewType.Sheet.self).find(FR2.self) - XCTAssertEqual(try fr2.text().string(), "FR2 type") - try await fr2.proceedInWorkflow() - - wait(for: [expectOnFinish], timeout: TestConstant.timeout) - } - // func testWorkflowItemsOfTheSameTypeCanBeFollowed() throws { // struct FR1: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? @@ -71,17 +81,17 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // ).inspection.inspect { fr1 in // let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// try await fr1.find(FR1.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) // try fr1.actualView().inspect { first in // XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) // try first.find(ViewType.Sheet.self).view(WorkflowItem, FR1>.self).actualView().inspect(model: model, launcher: launcher) { second in // XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) -// try await second.find(FR1.self).proceedInWorkflow() +// XCTAssertNoThrow(try second.find(FR1.self).actualView().proceedInWorkflow()) // try second.actualView().inspect { second in // XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) // try second.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { third in -// try await third.find(FR1.self).proceedInWorkflow() +// XCTAssertNoThrow(try third.find(FR1.self).actualView().proceedInWorkflow()) // try third.actualView().inspect { third in // XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) @@ -152,7 +162,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // ).inspection.inspect { fr_1 in // model = (Mirror(reflecting: try fr_1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // launcher = (Mirror(reflecting: try fr_1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// try await fr_1.find(FR1.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr_1.find(FR1.self).actualView().proceedInWorkflow()) // try fr_1.actualView().inspect { fr_1 in // XCTAssert(try fr_1.find(ViewType.Sheet.self).isPresented()) // fr1 = fr_1 @@ -165,7 +175,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // // try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr_2 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// try await fr_2.find(FR2.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr_2.find(FR2.self).actualView().proceedInWorkflow()) // try fr_2.actualView().inspect { fr_2 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr_2.find(ViewType.Sheet.self).isPresented()) @@ -176,7 +186,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // removeQueuedExpectations() // // try fr2.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>.self).actualView().inspect(model: model, launcher: launcher) { fr_3 in -// try await fr_3.find(FR3.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr_3.find(FR3.self).actualView().proceedInWorkflow()) // try fr_3.actualView().inspect { fr_3 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -188,7 +198,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // removeQueuedExpectations() // // try fr3.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>.self).actualView().inspect(model: model, launcher: launcher) { fr_4 in -// try await fr_4.find(FR4.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr_4.find(FR4.self).actualView().proceedInWorkflow()) // try fr_4.actualView().inspect { fr_4 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -201,7 +211,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // removeQueuedExpectations() // // try fr4.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>.self).actualView().inspect(model: model, launcher: launcher) { fr_5 in -// try await fr_5.find(FR5.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr_5.find(FR5.self).actualView().proceedInWorkflow()) // try fr_5.actualView().inspect { fr_5 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -215,7 +225,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // removeQueuedExpectations() // // try fr5.find(ViewType.Sheet.self).view(WorkflowItem, FR6>.self).actualView().inspect(model: model, launcher: launcher) { fr_6 in -// try await fr_6.find(FR6.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr_6.find(FR6.self).actualView().proceedInWorkflow()) // try fr_6.actualView().inspect { fr_6 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -230,7 +240,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // removeQueuedExpectations() // // try fr6.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr7 in -// try await fr7.find(FR7.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr7.find(FR7.self).actualView().proceedInWorkflow()) // try fr7.actualView().inspect { fr7 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -269,7 +279,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue // XCTAssertThrowsError(try fr1.find(FR1.self).actualView()) // try fr1.view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// try await fr2.find(FR2.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) // try fr2.actualView().inspect { fr2 in // try fr2.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in // XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) @@ -307,7 +317,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // ).inspection.inspect { fr1 in // let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// try await fr1.find(FR1.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) // try fr1.actualView().inspect { fr1 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in @@ -353,7 +363,7 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // ).inspection.inspect { fr1 in // let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// try await fr1.find(FR1.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) // try fr1.actualView().inspect { fr1 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR3>, FR2>.self).view(WorkflowItem, FR3>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr4 in @@ -397,17 +407,17 @@ final class SwiftCurrent_ModalTests: XCTestCase, Scene { // }).inspection.inspect { fr1 in // let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue // let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// try await fr1.find(FR1.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) // try fr1.actualView().inspect { fr1 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) // try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in // XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// try await fr2.find(FR2.self).proceedInWorkflow() +// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) // } // } // } // // wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) // } - -} +// +//} From 703daed4e3d7c89529dca217426e67b6b8004bbf Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Mon, 7 Feb 2022 11:56:29 -0700 Subject: [PATCH 17/37] [async-swiftui-tests] - Got a bunch more tests passing, still a long ways to go and some issues with navs and modals - TT --- Package.swift | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../SwiftCurrent_SwiftUITests.swift | 1393 ++++++++--------- .../ViewInspector/ViewHostingExtensions.swift | 4 + 4 files changed, 680 insertions(+), 723 deletions(-) diff --git a/Package.swift b/Package.swift index 782bdcec9..e48d0a0de 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/mattgallagher/CwlCatchException.git", from: Version("2.0.0-beta.1")), .package(url: "https://github.com/apple/swift-algorithms", .upToNextMajor(from: "0.0.1")), .package(url: "https://github.com/sindresorhus/ExceptionCatcher", from: "2.0.0"), - .package(url: "https://github.com/nalexn/ViewInspector.git", from: "0.9.0") + .package(url: "https://github.com/nalexn/ViewInspector.git", from: "0.9.1") ], targets: [ .target( diff --git a/SwiftCurrent.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SwiftCurrent.xcworkspace/xcshareddata/swiftpm/Package.resolved index cbac56caa..e32b92764 100644 --- a/SwiftCurrent.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/SwiftCurrent.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -78,8 +78,8 @@ "repositoryURL": "https://github.com/nalexn/ViewInspector.git", "state": { "branch": null, - "revision": "0d546878902bdde8c4682141f848a9dc44e04ba6", - "version": "0.9.0" + "revision": "6b88c4ec1fa20cf38f2138052e63c8e79df5d76e", + "version": "0.9.1" } } ] diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift index a61a43c7b..55cf46630 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift @@ -1,455 +1,416 @@ -//// -//// SwiftCurrent_SwiftUIConsumerTests.swift -//// SwiftCurrent -//// -//// Created by Tyler Thompson on 7/12/21. -//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -//// // -//import XCTest -//import SwiftUI -//import ViewInspector -// -//import SwiftCurrent -//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { -// override func tearDownWithError() throws { -// removeQueuedExpectations() -// } -// -// func testWorkflowCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowCanHaveMultipleOnFinishClosures() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// let expectOnFinish1 = expectation(description: "OnFinish1 called") -// let expectOnFinish2 = expectation(description: "OnFinish2 called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) -// } -// .onFinish { _ in -// expectOnFinish1.fulfill() -// }.onFinish { _ in -// expectOnFinish2.fulfill() -// }).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// } -// -// wait(for: [expectOnFinish1, expectOnFinish2, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowCanFinishMultipleTimes() throws { -// throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// let expectOnFinish1 = expectation(description: "OnFinish1 called") -// let expectOnFinish2 = expectation(description: "OnFinish2 called") -// var showWorkflow = Binding(wrappedValue: true) -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: showWorkflow) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// .onFinish { _ in -// showWorkflow.wrappedValue = false -// showWorkflow.update() -// }).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// showWorkflow.wrappedValue = true -// showWorkflow.update() -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// showWorkflow.wrappedValue = true -// showWorkflow.update() -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// } -// -// wait(for: [expectOnFinish1, expectOnFinish2, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowPassesArgumentsToTheFirstItem() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// let stringProperty: String -// init(with: String) { -// self.stringProperty = with -// } -// var body: some View { Text("FR1 type") } -// } -// let expected = UUID().uuidString -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true), startingArgs: expected) { -// thenProceed(with: FR1.self) -// }) -// .inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().stringProperty, expected) -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowPassesArgumentsToTheFirstItem_WhenThatFirstItemTakesInAnyWorkflowPassedArgs() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// let property: AnyWorkflow.PassedArgs -// init(with: AnyWorkflow.PassedArgs) { -// self.property = with -// } -// var body: some View { Text("FR1 type") } -// } -// let expected = UUID().uuidString -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true), startingArgs: expected) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR1.self) -// } -// }).inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property.extractArgs(defaultValue: nil) as? String, expected) -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowPassesArgumentsToTheFirstItem_WhenThatFirstItemTakesInAnyWorkflowPassedArgs_AndTheLaunchArgsAreAnyWorkflowPassedArgs() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// typealias WorkflowOutput = AnyWorkflow.PassedArgs -// var _workflowPointer: AnyFlowRepresentable? -// let property: AnyWorkflow.PassedArgs -// init(with: AnyWorkflow.PassedArgs) { -// self.property = with -// } -// var body: some View { Text("FR1 type") } -// } -// let expected = UUID().uuidString -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true), startingArgs: AnyWorkflow.PassedArgs.args(expected)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR1.self) -// } -// }).inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property.extractArgs(defaultValue: nil) as? String, expected) -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowPassesArgumentsToAllItems() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// typealias WorkflowOutput = Int -// var _workflowPointer: AnyFlowRepresentable? -// let property: String -// init(with: String) { -// self.property = with -// } -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// typealias WorkflowOutput = Bool -// var _workflowPointer: AnyFlowRepresentable? -// let property: Int -// init(with: Int) { -// self.property = with -// } -// var body: some View { Text("FR1 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// typealias WorkflowOutput = String -// var _workflowPointer: AnyFlowRepresentable? -// let property: Bool -// init(with: Bool) { -// self.property = with -// } -// var body: some View { Text("FR1 type") } -// } -// let expectedFR1 = UUID().uuidString -// let expectedFR2 = Int.random(in: 1...10) -// let expectedFR3 = Bool.random() -// let expectedEnd = UUID().uuidString -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedFR1) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) -// } -// } -// } -// .onFinish { -// XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedEnd) -// }).inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().property, expectedFR1) -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow(expectedFR2)) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR2.self).actualView().property, expectedFR2) -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow(expectedFR3)) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR3.self).actualView().property, expectedFR3) -// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow(expectedEnd)) -// } -// } -// } -// -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testLargeWorkflowCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// struct FR5: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR5 type") } -// } -// struct FR6: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR6 type") } -// } -// struct FR7: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR7 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) { -// thenProceed(with: FR5.self) { -// thenProceed(with: FR6.self) { -// thenProceed(with: FR7.self) -// } -// } -// } -// } -// } -// } -// } -// ).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR4.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR5.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR6.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR7.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowOnlyShowsOneViewAtATime() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR2.self) -// } -// } -// } -// } -// ).inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertNoThrow(try fr4.find(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// } -// XCTAssertThrowsError(try fr1.find(ViewType.Text.self, skipFound: 1)) -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testMovingBiDirectionallyInAWorkflow() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// } -// } -// } -// ).inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().backUpInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().backUpInWorkflow()) -// try fr2.actualView().inspect { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspectWrapped { fr3 in -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspectWrapped { fr4 in -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowSetsBindingBooleanToFalseWhenAbandoned() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// let isLaunched = Binding(wrappedValue: true) -// let expectOnAbandon = expectation(description: "OnAbandon called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: isLaunched) { -// thenProceed(with: FR1.self)} -// .onAbandon { -// XCTAssertFalse(isLaunched.wrappedValue) -// expectOnAbandon.fulfill() -// }).inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().workflow?.abandon()) -// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) -// } -// -// wait(for: [expectOnAbandon, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowCanHaveMultipleOnAbandonCallbacks() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// let isLaunched = Binding(wrappedValue: true) -// let expectOnAbandon1 = expectation(description: "OnAbandon1 called") -// let expectOnAbandon2 = expectation(description: "OnAbandon2 called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: isLaunched) { -// thenProceed(with: FR1.self) -// } -// .onAbandon { -// XCTAssertFalse(isLaunched.wrappedValue) -// expectOnAbandon1.fulfill() -// }.onAbandon { -// XCTAssertFalse(isLaunched.wrappedValue) -// expectOnAbandon2.fulfill() -// }).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().workflow?.abandon()) -// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) -// } -// -// wait(for: [expectOnAbandon1, expectOnAbandon2, expectViewLoaded], timeout: TestConstant.timeout) -// } +// SwiftCurrent_SwiftUIConsumerTests.swift +// SwiftCurrent +// +// Created by Tyler Thompson on 7/12/21. +// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +// + +import XCTest +import SwiftUI +import ViewInspector + +import SwiftCurrent +@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work + +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { + func testWorkflowCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + let expectOnFinish = expectation(description: "OnFinish called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + .onFinish { _ in + expectOnFinish.fulfill() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + let fr2 = try launcher.find(FR2.self) + XCTAssertEqual(try fr2.text().string(), "FR2 type") + XCTAssertNoThrow(try fr2.actualView().proceedInWorkflow()) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testWorkflowCanHaveMultipleOnFinishClosures() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + let expectOnFinish1 = expectation(description: "OnFinish1 called") + let expectOnFinish2 = expectation(description: "OnFinish2 called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) + } + .onFinish { _ in + expectOnFinish1.fulfill() + }.onFinish { _ in + expectOnFinish2.fulfill() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + + wait(for: [expectOnFinish1, expectOnFinish2], timeout: TestConstant.timeout) + } + + func testWorkflowCanFinishMultipleTimes() async throws { + throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + @MainActor struct TestUtils { + static var showWorkflow = Binding(wrappedValue: true) + } + let expectOnFinish1 = expectation(description: "OnFinish1 called") + let expectOnFinish2 = expectation(description: "OnFinish2 called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: TestUtils.showWorkflow) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + .onFinish { _ in + TestUtils.showWorkflow.wrappedValue = false + TestUtils.showWorkflow.update() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + await MainActor.run { + TestUtils.showWorkflow.wrappedValue = true + TestUtils.showWorkflow.update() + } + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + await MainActor.run { + TestUtils.showWorkflow.wrappedValue = true + TestUtils.showWorkflow.update() + } + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + + wait(for: [expectOnFinish1, expectOnFinish2], timeout: TestConstant.timeout) + } + + func testWorkflowPassesArgumentsToTheFirstItem() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + let stringProperty: String + init(with: String) { + self.stringProperty = with + } + var body: some View { Text("FR1 type") } + } + let expected = UUID().uuidString + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expected) { + thenProceed(with: FR1.self) + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).actualView().stringProperty, expected) + } + + func testWorkflowPassesArgumentsToTheFirstItem_WhenThatFirstItemTakesInAnyWorkflowPassedArgs() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + let property: AnyWorkflow.PassedArgs + init(with: AnyWorkflow.PassedArgs) { + self.property = with + } + var body: some View { Text("FR1 type") } + } + let expected = UUID().uuidString + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expected) { + thenProceed(with: FR1.self) { + thenProceed(with: FR1.self) + } + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).actualView().property.extractArgs(defaultValue: nil) as? String, expected) + } + + func testWorkflowPassesArgumentsToTheFirstItem_WhenThatFirstItemTakesInAnyWorkflowPassedArgs_AndTheLaunchArgsAreAnyWorkflowPassedArgs() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + typealias WorkflowOutput = AnyWorkflow.PassedArgs + var _workflowPointer: AnyFlowRepresentable? + let property: AnyWorkflow.PassedArgs + init(with: AnyWorkflow.PassedArgs) { + self.property = with + } + var body: some View { Text("FR1 type") } + } + let expected = UUID().uuidString + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: AnyWorkflow.PassedArgs.args(expected)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR1.self) + } + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).actualView().property.extractArgs(defaultValue: nil) as? String, expected) + } + + func testWorkflowPassesArgumentsToAllItems() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + typealias WorkflowOutput = Int + var _workflowPointer: AnyFlowRepresentable? + let property: String + init(with: String) { + self.property = with + } + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + typealias WorkflowOutput = Bool + var _workflowPointer: AnyFlowRepresentable? + let property: Int + init(with: Int) { + self.property = with + } + var body: some View { Text("FR1 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + typealias WorkflowOutput = String + var _workflowPointer: AnyFlowRepresentable? + let property: Bool + init(with: Bool) { + self.property = with + } + var body: some View { Text("FR1 type") } + } + let expectedFR1 = UUID().uuidString + let expectedFR2 = Int.random(in: 1...10) + let expectedFR3 = Bool.random() + let expectedEnd = UUID().uuidString + + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedFR1) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) + } + } + } + .onFinish { + XCTAssertEqual($0.extractArgs(defaultValue: nil) as? String, expectedEnd) + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).actualView().property, expectedFR1) + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow(expectedFR2)) + XCTAssertEqual(try launcher.find(FR2.self).actualView().property, expectedFR2) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow(expectedFR3)) + XCTAssertEqual(try launcher.find(FR3.self).actualView().property, expectedFR3) + XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow(expectedEnd)) + } + + func testLargeWorkflowCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + struct FR5: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR5 type") } + } + struct FR6: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR6 type") } + } + struct FR7: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR7 type") } + } + + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) { + thenProceed(with: FR5.self) { + thenProceed(with: FR6.self) { + thenProceed(with: FR7.self) + } + } + } + } + } + } + } + }.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR4.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR5.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR6.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR7.self).actualView().proceedInWorkflow()) + } + + func testWorkflowOnlyShowsOneViewAtATime() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR2.self) + } + } + } + } + }.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + XCTAssertThrowsError(try launcher.find(ViewType.Text.self, skipFound: 1)) + } + + func testMovingBiDirectionallyInAWorkflow() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + } + } + } + }.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().backUpInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR3.self).actualView().backUpInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR4.self).actualView().proceedInWorkflow()) + } + + func testWorkflowSetsBindingBooleanToFalseWhenAbandoned() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + let isLaunched = Binding(wrappedValue: true) + let expectOnAbandon = expectation(description: "OnAbandon called") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: isLaunched) { + thenProceed(with: FR1.self)} + .onAbandon { + XCTAssertFalse(isLaunched.wrappedValue) + expectOnAbandon.fulfill() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") + try await launcher.find(FR1.self).abandonWorkflow() + XCTAssertThrowsError(try launcher.find(FR1.self)) + + wait(for: [expectOnAbandon], timeout: TestConstant.timeout) + } + + func testWorkflowCanHaveMultipleOnAbandonCallbacks() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + let isLaunched = Binding(wrappedValue: true) + let expectOnAbandon1 = expectation(description: "OnAbandon1 called") + let expectOnAbandon2 = expectation(description: "OnAbandon2 called") + + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: isLaunched) { + thenProceed(with: FR1.self) + } + .onAbandon { + XCTAssertFalse(isLaunched.wrappedValue) + expectOnAbandon1.fulfill() + }.onAbandon { + XCTAssertFalse(isLaunched.wrappedValue) + expectOnAbandon2.fulfill() + } + }.hostAndInspect(with: \.inspection) + + try await launcher.find(FR1.self).abandonWorkflow() + XCTAssertThrowsError(try launcher.find(FR1.self)) + + wait(for: [expectOnAbandon1, expectOnAbandon2], timeout: TestConstant.timeout) + } // // func testWorkflowCanHaveModifiers() throws { // struct FR1: View, FlowRepresentable, Inspectable { @@ -471,272 +432,264 @@ // wait(for: [expectViewLoaded], timeout: TestConstant.timeout) // } // -// func testWorkflowRelaunchesWhenSubsequentlyLaunched() throws { -// throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// -// func customModifier() -> Self { self } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// -// let binding = Binding(wrappedValue: true) -// let workflowView = WorkflowLauncher(isLaunched: binding) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// -// binding.wrappedValue = false -// XCTAssertThrowsError(try viewUnderTest.find(FR1.self)) -// XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) -// -// binding.wrappedValue = true -// XCTAssertNoThrow(try viewUnderTest.callOnChange(newValue: false)) -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self)) -// XCTAssertThrowsError(try viewUnderTest.find(FR2.self)) -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowRelaunchesWhenAbandoned_WithAConstantOfTrue() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// -// func abandon() { -// workflow?.abandon() -// } -// } -// let onFinishCalled = expectation(description: "onFinish Called") -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// .onFinish { _ in -// onFinishCalled.fulfill() -// } -// -// let expectViewLoaded = ViewHosting.loadView(workflowView).inspection.inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().abandon()) -// XCTAssertThrowsError(try fr2.find(FR2.self)) -// try fr1.actualView().inspect { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspectWrapped { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded, onFinishCalled], timeout: TestConstant.timeout) -// } -// -// func testWorkflowCanHaveAPassthroughRepresentable() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// typealias WorkflowOutput = AnyWorkflow.PassedArgs -// var _workflowPointer: AnyFlowRepresentable? -// private let data: AnyWorkflow.PassedArgs -// var body: some View { Text("FR1 type") } -// -// init(with data: AnyWorkflow.PassedArgs) { -// self.data = data -// } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// init(with str: String) { } -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectedArgs = UUID().uuidString -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// } -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow(.args(expectedArgs))) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowCanConvertAnyArgsToCorrectTypeForFirstItem() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// let data: String -// -// var body: some View { Text("FR1 type") } -// -// init(with data: String) { -// self.data = data -// } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// init(with str: String) { } -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectedArgs = UUID().uuidString -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true), startingArgs: AnyWorkflow.PassedArgs.args(expectedArgs)) { -// thenProceed(with: FR1.self) -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") -// XCTAssertEqual(try viewUnderTest.find(FR1.self).actualView().data, expectedArgs) -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowCanHaveAPassthroughRepresentableInTheMiddle() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// typealias WorkflowOutput = AnyWorkflow.PassedArgs -// var _workflowPointer: AnyFlowRepresentable? -// private let data: AnyWorkflow.PassedArgs -// var body: some View { Text("FR2 type") } -// -// init(with data: AnyWorkflow.PassedArgs) { -// self.data = data -// } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// let str: String -// init(with str: String) { -// self.str = str -// } -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type, \(str)") } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectedArgs = UUID().uuidString -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) -// } -// } -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR1.self).text().string(), "FR1 type") -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).actualView().proceedInWorkflow()) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR2.self).text().string(), "FR2 type") -// XCTAssertNoThrow(try viewUnderTest.find(FR2.self).actualView().proceedInWorkflow(.args(expectedArgs))) -// try viewUnderTest.actualView().inspectWrapped { viewUnderTest in -// XCTAssertEqual(try viewUnderTest.find(FR3.self).text().string(), "FR3 type, \(expectedArgs)") -// XCTAssertNoThrow(try viewUnderTest.find(FR3.self).actualView().proceedInWorkflow()) -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowCorrectlyHandlesState() throws { -// struct FR1: View, FlowRepresentable { -// weak var _workflowPointer: AnyFlowRepresentable? -// -// var body: some View { -// Button("Proceed") { proceedInWorkflow() } -// } -// } -// -// let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) -// } -// -// typealias WorkflowViewContent = State> -// let content = try XCTUnwrap(Mirror(reflecting: workflowView).descendant("_content") as? WorkflowViewContent) -// -// // Note: Only add to these exceptions if you are *certain* the property should not be @State. Err on the side of the property being @State -// let exceptions = ["_model", "_launcher", "_location", "_value", "inspection", "_presentation"] -// -// let mirror = Mirror(reflecting: content.wrappedValue) -// -// XCTAssertGreaterThan(mirror.children.count, 0) -// -// mirror.children.forEach { -// guard let label = $0.label, !exceptions.contains(label) else { return } -// XCTAssert($0.value is StateIdentifiable, "Property named: \(label) was note @State") -// } -// } -// -// func testWorkflowCanHaveADelayedLaunch() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// weak var _workflowPointer: AnyFlowRepresentable? -// -// var body: some View { -// Button("Proceed") { proceedInWorkflow() } -// } -// } -// -// struct Wrapper: View, Inspectable { -// @State var showingWorkflow = false -// let inspection = Inspection() -// var body: some View { -// VStack { -// Button("") { showingWorkflow = true } -// WorkflowLauncher(isLaunched: $showingWorkflow) { -// thenProceed(with: FR1.self) -// } -// } -// .onReceive(inspection.notice) { inspection.visit(self, $0) } -// } -// } -// -// let exp = ViewHosting.loadView(Wrapper()).inspection.inspect { view in -// let stack = try view.vStack() -// let launcher = try stack.view(WorkflowLauncher>.self, 1) -// XCTAssertThrowsError(try launcher.view(WorkflowItem.self)) -// XCTAssertNoThrow(try stack.button(0).tap()) -// XCTAssertNoThrow(try launcher.view(WorkflowItem.self)) -// } -// -// wait(for: [exp], timeout: TestConstant.timeout) -// } -//} -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//protocol StateIdentifiable { } -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//extension State: StateIdentifiable { -// -//} + func testWorkflowRelaunchesWhenSubsequentlyLaunched() async throws { + throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + + func customModifier() -> Self { self } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + + @MainActor struct TestUtils { + static let binding = Binding(wrappedValue: true) + } + + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: TestUtils.binding) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + }.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + + await MainActor.run { TestUtils.binding.wrappedValue = false } + XCTAssertThrowsError(try launcher.find(FR1.self)) + XCTAssertThrowsError(try launcher.find(FR2.self)) + + await MainActor.run { TestUtils.binding.wrappedValue = true } + XCTAssertNoThrow(try launcher.callOnChange(newValue: false)) + XCTAssertNoThrow(try launcher.find(FR1.self)) + XCTAssertThrowsError(try launcher.find(FR2.self)) + + } + + func testWorkflowRelaunchesWhenAbandoned_WithAConstantOfTrue() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + + func abandon() { + workflow?.abandon() + } + } + let onFinishCalled = expectation(description: "onFinish Called") + + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + .onFinish { _ in + onFinishCalled.fulfill() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().abandon()) + XCTAssertThrowsError(try launcher.find(FR2.self)) + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + + wait(for: [onFinishCalled], timeout: TestConstant.timeout) + } + + func testWorkflowCanHaveAPassthroughRepresentable() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + typealias WorkflowOutput = AnyWorkflow.PassedArgs + var _workflowPointer: AnyFlowRepresentable? + private let data: AnyWorkflow.PassedArgs + var body: some View { Text("FR1 type") } + + init(with data: AnyWorkflow.PassedArgs) { + self.data = data + } + } + struct FR2: View, FlowRepresentable, Inspectable { + init(with str: String) { } + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + let expectOnFinish = expectation(description: "OnFinish called") + let expectedArgs = UUID().uuidString + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: expectedArgs) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } + .onFinish { _ in + expectOnFinish.fulfill() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow(.args(expectedArgs))) + XCTAssertEqual(try launcher.find(FR2.self).text().string(), "FR2 type") + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testWorkflowCanConvertAnyArgsToCorrectTypeForFirstItem() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + let data: String + + var body: some View { Text("FR1 type") } + + init(with data: String) { + self.data = data + } + } + struct FR2: View, FlowRepresentable, Inspectable { + init(with str: String) { } + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + let expectOnFinish = expectation(description: "OnFinish called") + let expectedArgs = UUID().uuidString + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: AnyWorkflow.PassedArgs.args(expectedArgs)) { + thenProceed(with: FR1.self) + } + .onFinish { _ in + expectOnFinish.fulfill() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") + XCTAssertEqual(try launcher.find(FR1.self).actualView().data, expectedArgs) + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testWorkflowCanHaveAPassthroughRepresentableInTheMiddle() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + typealias WorkflowOutput = AnyWorkflow.PassedArgs + var _workflowPointer: AnyFlowRepresentable? + private let data: AnyWorkflow.PassedArgs + var body: some View { Text("FR2 type") } + + init(with data: AnyWorkflow.PassedArgs) { + self.data = data + } + } + struct FR3: View, FlowRepresentable, Inspectable { + let str: String + init(with str: String) { + self.str = str + } + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type, \(str)") } + } + let expectOnFinish = expectation(description: "OnFinish called") + let expectedArgs = UUID().uuidString + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) + } + } + } + .onFinish { _ in + expectOnFinish.fulfill() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") + XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + XCTAssertEqual(try launcher.find(FR2.self).text().string(), "FR2 type") + XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow(.args(expectedArgs))) + XCTAssertEqual(try launcher.find(FR3.self).text().string(), "FR3 type, \(expectedArgs)") + XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testWorkflowCorrectlyHandlesState() throws { + struct FR1: View, FlowRepresentable { + weak var _workflowPointer: AnyFlowRepresentable? + + var body: some View { + Button("Proceed") { proceedInWorkflow() } + } + } + + let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) + } + + typealias WorkflowViewContent = State> + let content = try XCTUnwrap(Mirror(reflecting: workflowView).descendant("_content") as? WorkflowViewContent) + + // Note: Only add to these exceptions if you are *certain* the property should not be @State. Err on the side of the property being @State + let exceptions = ["_model", "_launcher", "_location", "_value", "inspection", "_presentation"] + + let mirror = Mirror(reflecting: content.wrappedValue) + + XCTAssertGreaterThan(mirror.children.count, 0) + + mirror.children.forEach { + guard let label = $0.label, !exceptions.contains(label) else { return } + XCTAssert($0.value is StateIdentifiable, "Property named: \(label) was note @State") + } + } + + func testWorkflowCanHaveADelayedLaunch() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + weak var _workflowPointer: AnyFlowRepresentable? + + var body: some View { + Button("Proceed") { proceedInWorkflow() } + } + } + + struct Wrapper: View, Inspectable { + @State var showingWorkflow = false + let inspection = Inspection() + var body: some View { + VStack { + Button("") { showingWorkflow = true } + WorkflowLauncher(isLaunched: $showingWorkflow) { + thenProceed(with: FR1.self) + } + } + .onReceive(inspection.notice) { inspection.visit(self, $0) } + } + } + + let wrapper = try await MainActor.run { Wrapper() }.hostAndInspect(with: \.inspection) + + let stack = try wrapper.vStack() + let launcher = try stack.view(WorkflowLauncher>.self, 1) + XCTAssertThrowsError(try launcher.view(WorkflowItem.self)) + XCTAssertNoThrow(try stack.button(0).tap()) + XCTAssertNoThrow(try launcher.view(WorkflowItem.self)) + } +} + +@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +protocol StateIdentifiable { } + +@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +extension State: StateIdentifiable { + +} diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index ae7ff0bda..0565d56af 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -77,6 +77,10 @@ extension InspectableView where View: CustomViewType & SingleViewContent, View.T func backUpInWorkflow() async throws { try await MainActor.run { try actualView().backUpInWorkflow() } } + + func abandonWorkflow() async throws { + try await MainActor.run { try actualView().workflow?.abandon() } + } } @available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) From b33b009726802f6863a899c5c5107ad140ae5182 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Mon, 7 Feb 2022 12:30:36 -0700 Subject: [PATCH 18/37] [async-swiftui-tests] - everything should compile now - TT --- .../UIKitInteropTests.swift | 3 +- .../Views/ContentViewTests.swift | 79 ++++++++++--------- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift index e7e1c286c..d67bb4784 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift @@ -91,7 +91,8 @@ final class UIKitInteropTests: XCTestCase, View { self.wait(for: [proceedCalled], timeout: TestConstant.timeout) - try workflowLauncher.actualView().inspectWrapped { fr1 in + #warning("Do not think this ever worked") + try workflowLauncher.actualView().getWrappedView().inspection.inspect { fr1 in XCTAssertNoThrow(try fr1.find(FR1.self)) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ContentViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ContentViewTests.swift index ee4bcc5db..afdd43558 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ContentViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ContentViewTests.swift @@ -22,43 +22,44 @@ final class ContentViewTests: XCTestCase { Container.default.removeAll() } - func testContentView() throws { - let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) - Container.default.register(UserDefaults.self) { _ in defaults } - var wf1: MapWorkflow! - var wf2: QRScannerWorkflow! - var wf3: ProfileWorkflow! - let exp = ViewHosting.loadView(ContentView()).inspection.inspect { view in - wf1 = try view.tabView().view(MapWorkflow.self, 0).actualView() - XCTAssertEqual(try view.tabView().view(MapWorkflow.self, 0).tabItem().label().title().text().string(), "Map") - wf2 = try view.tabView().view(QRScannerWorkflow.self, 1).actualView() - XCTAssertEqual(try view.tabView().view(QRScannerWorkflow.self, 1).tabItem().label().title().text().string(), "QR Scanner") - wf3 = try view.tabView().view(ProfileWorkflow.self, 2).actualView() - XCTAssertEqual(try view.tabView().view(ProfileWorkflow.self, 2).tabItem().label().title().text().string(), "Profile") - } - wait(for: [exp], timeout: TestConstant.timeout) - XCTAssertNotNil(wf1) - XCTAssertNotNil(wf2) - XCTAssertNotNil(wf3) - wait(for: [ - ViewHosting.loadView(wf1).inspection.inspect { view in - XCTAssertNoThrow(try view.find(MapFeatureOnboardingView.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(MapFeatureView.self)) - } - }, - ViewHosting.loadView(wf2).inspection.inspect { view in - XCTAssertNoThrow(try view.find(QRScannerFeatureOnboardingView.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(QRScannerFeatureView.self)) - } - }, - ViewHosting.loadView(wf3).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ProfileFeatureOnboardingView.self).actualView().proceedInWorkflow()) - try view.actualView().inspectWrapped { view in - XCTAssertNoThrow(try view.find(ProfileFeatureView.self)) - } - } - ].compactMap { $0 }, timeout: TestConstant.timeout) - } + #warning("FIXME") +// func testContentView() throws { +// let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) +// Container.default.register(UserDefaults.self) { _ in defaults } +// var wf1: MapWorkflow! +// var wf2: QRScannerWorkflow! +// var wf3: ProfileWorkflow! +// let exp = ViewHosting.loadView(ContentView()).inspection.inspect { view in +// wf1 = try view.tabView().view(MapWorkflow.self, 0).actualView() +// XCTAssertEqual(try view.tabView().view(MapWorkflow.self, 0).tabItem().label().title().text().string(), "Map") +// wf2 = try view.tabView().view(QRScannerWorkflow.self, 1).actualView() +// XCTAssertEqual(try view.tabView().view(QRScannerWorkflow.self, 1).tabItem().label().title().text().string(), "QR Scanner") +// wf3 = try view.tabView().view(ProfileWorkflow.self, 2).actualView() +// XCTAssertEqual(try view.tabView().view(ProfileWorkflow.self, 2).tabItem().label().title().text().string(), "Profile") +// } +// wait(for: [exp], timeout: TestConstant.timeout) +// XCTAssertNotNil(wf1) +// XCTAssertNotNil(wf2) +// XCTAssertNotNil(wf3) +// wait(for: [ +// ViewHosting.loadView(wf1).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(MapFeatureOnboardingView.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(MapFeatureView.self)) +// } +// }, +// ViewHosting.loadView(wf2).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(QRScannerFeatureOnboardingView.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(QRScannerFeatureView.self)) +// } +// }, +// ViewHosting.loadView(wf3).inspection.inspect { view in +// XCTAssertNoThrow(try view.find(ProfileFeatureOnboardingView.self).actualView().proceedInWorkflow()) +// try view.actualView().inspectWrapped { view in +// XCTAssertNoThrow(try view.find(ProfileFeatureView.self)) +// } +// } +// ].compactMap { $0 }, timeout: TestConstant.timeout) +// } } From f784f082b7f360998b65e922848d920811d71d28 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Mon, 7 Feb 2022 12:46:29 -0700 Subject: [PATCH 19/37] [async-swiftui-tests] - Does macos 12 work for GitHub actions yet? - TT --- .github/workflows/PR_CI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/PR_CI.yml b/.github/workflows/PR_CI.yml index 39bbb777a..9e62c2335 100644 --- a/.github/workflows/PR_CI.yml +++ b/.github/workflows/PR_CI.yml @@ -4,7 +4,7 @@ on: [ pull_request ] jobs: test: - runs-on: macos-11 + runs-on: macos-12 env: working-directory: .github DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer @@ -56,4 +56,4 @@ jobs: - uses: actions/checkout@v2 - name: Swiftlint run: bundle exec fastlane lint - working-directory: ${{ env.working-directory }} \ No newline at end of file + working-directory: ${{ env.working-directory }} From 5361831c145d5e83bb8eaafaaf125d4539c40af8 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Mon, 7 Feb 2022 13:10:44 -0700 Subject: [PATCH 20/37] [async-swiftui-tests] - disable tests in the pipeline, because macOS 12 is not available - TT --- .github/workflows/PR_CI.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/PR_CI.yml b/.github/workflows/PR_CI.yml index 9e62c2335..0d793c1ea 100644 --- a/.github/workflows/PR_CI.yml +++ b/.github/workflows/PR_CI.yml @@ -5,6 +5,7 @@ on: [ pull_request ] jobs: test: runs-on: macos-12 + if: ${{ false }} # disable for now, until macos-12 because available env: working-directory: .github DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer From dce4ab741d30d0543469bdbe5dbcef71dcbd7ac7 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Mon, 7 Feb 2022 13:34:42 -0700 Subject: [PATCH 21/37] [async-swiftui-tests] - Refactored some SwiftUIExample tests, including one that never could have worked correctly - TT --- .../UIKitInteropTests.swift | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift index d67bb4784..e7c7bc00b 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift @@ -21,17 +21,21 @@ import SwiftCurrent_UIKit @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) final class UIKitInteropTests: XCTestCase, View { - func testPuttingAUIKitViewInsideASwiftUIWorkflow() throws { + func testPuttingAUIKitViewInsideASwiftUIWorkflow() async throws { let launchArgs = UUID().uuidString - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: launchArgs) { - thenProceed(with: UIKitInteropProgrammaticViewController.self) + + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: launchArgs) { + thenProceed(with: UIKitInteropProgrammaticViewController.self) + } } - var vc: UIKitInteropProgrammaticViewController! + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() - let exp = ViewHosting.loadView(workflowView).inspection.inspect { workflowLauncher in - let wrapper = try workflowLauncher.view(ViewControllerWrapper.self) + try await MainActor.run { + let wrapper = try launcher.view(ViewControllerWrapper.self) let context = unsafeBitCast(FakeContext(), to: UIViewControllerRepresentableContext>.self) - vc = try wrapper.actualView().makeUIViewController(context: context) + var vc = try wrapper.actualView().makeUIViewController(context: context) vc.removeFromParent() vc.loadOnDevice() @@ -44,60 +48,52 @@ final class UIKitInteropTests: XCTestCase, View { } XCTAssertEqual(vc.saveButton?.willRespondToUser, true) - XCTAssertEqual(vc?.emailTextField?.willRespondToUser, true) + XCTAssertEqual(vc.emailTextField?.willRespondToUser, true) vc.emailTextField?.simulateTouch() - vc.emailTextField?.simulateTyping(vc?.welcomeLabel?.text) + vc.emailTextField?.simulateTyping(vc.welcomeLabel?.text) vc.saveButton?.simulateTouch() self.wait(for: [proceedCalled], timeout: TestConstant.timeout) } - - wait(for: [exp], timeout: TestConstant.timeout) } - func testPuttingAUIKitViewInsideASwiftUIWorkflowWithOtherSwiftUIViews() throws { + func testPuttingAUIKitViewInsideASwiftUIWorkflowWithOtherSwiftUIViews() async throws { struct FR1: View, FlowRepresentable, Inspectable { weak var _workflowPointer: AnyFlowRepresentable? - var body: some View { EmptyView() } + let str: String + init(with str: String) { + self.str = str + } + var body: some View { Text(str) } } let launchArgs = UUID().uuidString - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: launchArgs) { - thenProceed(with: UIKitInteropProgrammaticViewController.self) { - thenProceed(with: FR1.self) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: launchArgs) { + thenProceed(with: UIKitInteropProgrammaticViewController.self) { + thenProceed(with: FR1.self) + } } } - var vc: UIKitInteropProgrammaticViewController! + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() - let exp = ViewHosting.loadView(workflowView).inspection.inspect { workflowLauncher in - let wrapper = try workflowLauncher.view(ViewControllerWrapper.self) + try await MainActor.run { + let wrapper = try launcher.view(ViewControllerWrapper.self) let context = unsafeBitCast(FakeContext(), to: UIViewControllerRepresentableContext>.self) - vc = try wrapper.actualView().makeUIViewController(context: context) + let vc = try wrapper.actualView().makeUIViewController(context: context) vc.removeFromParent() vc.loadOnDevice() XCTAssertUIViewControllerDisplayed(isInstance: vc) - let proceedCalled = self.expectation(description: "proceedCalled") - vc.proceedInWorkflowStorage = { args in - XCTAssertEqual(args.extractArgs(defaultValue: nil) as? String, "Welcome \(launchArgs)!") - proceedCalled.fulfill() - } - XCTAssertEqual(vc.saveButton?.willRespondToUser, true) - XCTAssertEqual(vc?.emailTextField?.willRespondToUser, true) + XCTAssertEqual(vc.emailTextField?.willRespondToUser, true) vc.emailTextField?.simulateTouch() - vc.emailTextField?.simulateTyping(vc?.welcomeLabel?.text) + vc.emailTextField?.simulateTyping(vc.welcomeLabel?.text) vc.saveButton?.simulateTouch() - self.wait(for: [proceedCalled], timeout: TestConstant.timeout) - - #warning("Do not think this ever worked") - try workflowLauncher.actualView().getWrappedView().inspection.inspect { fr1 in - XCTAssertNoThrow(try fr1.find(FR1.self)) - } + XCTAssertEqual(try launcher.find(FR1.self).text().string(), "Welcome \(launchArgs)!") } - - wait(for: [exp], timeout: TestConstant.timeout) } func testPuttingAUIKitViewThatDoesNotTakeInDataInsideASwiftUIWorkflow() throws { From 9aaed87c3077bc846cb860a1d27622677244db42 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Mon, 7 Feb 2022 13:52:09 -0700 Subject: [PATCH 22/37] [async-swiftui-tests] - Refactored all UIKit interop tests - TT --- .../UIKitInteropTests.swift | 172 +++++++++--------- 1 file changed, 88 insertions(+), 84 deletions(-) diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift index e7c7bc00b..c4f272550 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/UIKitInteropTests.swift @@ -96,7 +96,7 @@ final class UIKitInteropTests: XCTestCase, View { } } - func testPuttingAUIKitViewThatDoesNotTakeInDataInsideASwiftUIWorkflow() throws { + func testPuttingAUIKitViewThatDoesNotTakeInDataInsideASwiftUIWorkflow() async throws { final class FR1: UIWorkflowItem, FlowRepresentable { let nextButton = UIButton() @@ -116,37 +116,39 @@ final class UIKitInteropTests: XCTestCase, View { nextButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true } } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) + + let workflowView = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) + } } - var vc: FR1! + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() - let exp = ViewHosting.loadView(workflowView).inspection.inspect { workflowLauncher in - let wrapper = try workflowLauncher.view(ViewControllerWrapper.self) + try await MainActor.run { + let wrapper = try workflowView.view(ViewControllerWrapper.self) let context = unsafeBitCast(FakeContext(), to: UIViewControllerRepresentableContext>.self) - vc = try wrapper.actualView().makeUIViewController(context: context) - } - - wait(for: [exp], timeout: TestConstant.timeout) + var vc = try wrapper.actualView().makeUIViewController(context: context) - vc.removeFromParent() - vc.loadOnDevice() + vc.removeFromParent() + vc.loadOnDevice() - XCTAssertUIViewControllerDisplayed(isInstance: vc) + XCTAssertUIViewControllerDisplayed(isInstance: vc) - let proceedCalled = expectation(description: "proceedCalled") - vc.proceedInWorkflowStorage = { _ in - proceedCalled.fulfill() - } + let proceedCalled = expectation(description: "proceedCalled") + vc.proceedInWorkflowStorage = { _ in + proceedCalled.fulfill() + } - XCTAssertEqual(vc.nextButton.willRespondToUser, true) - vc.nextButton.simulateTouch() + XCTAssertEqual(vc.nextButton.willRespondToUser, true) + vc.nextButton.simulateTouch() - wait(for: [proceedCalled], timeout: TestConstant.timeout) + wait(for: [proceedCalled], timeout: TestConstant.timeout) + } } - func testWorkflowPointerIsSetBeforeShouldLoadIsCalled() throws { + func testWorkflowPointerIsSetBeforeShouldLoadIsCalled() async throws { final class FR1: UIWorkflowItem, FlowRepresentable { func shouldLoad() -> Bool { proceedInWorkflow("FR1") @@ -160,88 +162,89 @@ final class UIKitInteropTests: XCTestCase, View { } required init?(coder: NSCoder) { nil } } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } } } - var vc: FR2! + .hostAndInspect(with: \.inspection) - let exp = ViewHosting.loadView(workflowView).inspection.inspect { workflowLauncher in - let wrapper = try workflowLauncher.find(ViewControllerWrapper.self) + try await MainActor.run { + let wrapper = try launcher.find(ViewControllerWrapper.self) let context = unsafeBitCast(FakeContext(), to: UIViewControllerRepresentableContext>.self) - vc = try wrapper.actualView().makeUIViewController(context: context) - } - - wait(for: [exp], timeout: TestConstant.timeout) - - vc.removeFromParent() - vc.loadOnDevice() + let vc = try wrapper.actualView().makeUIViewController(context: context) + vc.removeFromParent() + vc.loadOnDevice() - XCTAssertUIViewControllerDisplayed(isInstance: vc) + XCTAssertUIViewControllerDisplayed(isInstance: vc) + } } - func testPuttingAUIKitViewFromStoryboardInsideASwiftUIWorkflow() throws { + func testPuttingAUIKitViewFromStoryboardInsideASwiftUIWorkflow() async throws { let launchArgs = UUID().uuidString - let workflowView = WorkflowLauncher(isLaunched: .constant(true), startingArgs: launchArgs) { - thenProceed(with: TestInputViewController.self) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: launchArgs) { + thenProceed(with: TestInputViewController.self) + } } - var vc: TestInputViewController! + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() - let exp = ViewHosting.loadView(workflowView).inspection.inspect { workflowLauncher in - let wrapper = try workflowLauncher.view(ViewControllerWrapper.self) + try await MainActor.run { + let wrapper = try launcher.view(ViewControllerWrapper.self) let context = unsafeBitCast(FakeContext(), to: UIViewControllerRepresentableContext>.self) - vc = try wrapper.actualView().makeUIViewController(context: context) - } - - wait(for: [exp], timeout: TestConstant.timeout) + var vc = try wrapper.actualView().makeUIViewController(context: context) - vc.removeFromParent() - vc.loadOnDevice() + vc.removeFromParent() + vc.loadOnDevice() - XCTAssertUIViewControllerDisplayed(isInstance: vc) + XCTAssertUIViewControllerDisplayed(isInstance: vc) - let proceedCalled = expectation(description: "proceedCalled") - vc.proceedInWorkflowStorage = { _ in - proceedCalled.fulfill() - } + let proceedCalled = expectation(description: "proceedCalled") + vc.proceedInWorkflowStorage = { _ in + proceedCalled.fulfill() + } - vc.proceedInWorkflow() + vc.proceedInWorkflow() - wait(for: [proceedCalled], timeout: TestConstant.timeout) + wait(for: [proceedCalled], timeout: TestConstant.timeout) + } } - func testPuttingAUIKitViewFromStoryboardThatDoesNotTakeInDataInsideASwiftUIWorkflow() throws { - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: TestNoInputViewController.self) + func testPuttingAUIKitViewFromStoryboardThatDoesNotTakeInDataInsideASwiftUIWorkflow() async throws { + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: TestNoInputViewController.self) + } } - var vc: TestNoInputViewController! + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() - let exp = ViewHosting.loadView(workflowView).inspection.inspect { workflowLauncher in - let wrapper = try workflowLauncher.view(ViewControllerWrapper.self) + try await MainActor.run { + let wrapper = try launcher.view(ViewControllerWrapper.self) let context = unsafeBitCast(FakeContext(), to: UIViewControllerRepresentableContext>.self) - vc = try wrapper.actualView().makeUIViewController(context: context) - } - - wait(for: [exp], timeout: TestConstant.timeout) + var vc = try wrapper.actualView().makeUIViewController(context: context) - vc.removeFromParent() - vc.loadOnDevice() + vc.removeFromParent() + vc.loadOnDevice() - XCTAssertUIViewControllerDisplayed(isInstance: vc) + XCTAssertUIViewControllerDisplayed(isInstance: vc) - let proceedCalled = expectation(description: "proceedCalled") - vc.proceedInWorkflowStorage = { _ in - proceedCalled.fulfill() - } + let proceedCalled = expectation(description: "proceedCalled") + vc.proceedInWorkflowStorage = { _ in + proceedCalled.fulfill() + } - vc.proceedInWorkflow() + vc.proceedInWorkflow() - wait(for: [proceedCalled], timeout: TestConstant.timeout) + wait(for: [proceedCalled], timeout: TestConstant.timeout) + } } - func testPuttingAUIKitViewThatDoesNotLoadInsideASwiftUIWorkflow() throws { + func testPuttingAUIKitViewThatDoesNotLoadInsideASwiftUIWorkflow() async throws { final class FR1: UIWorkflowItem, FlowRepresentable { func shouldLoad() -> Bool { false } } @@ -253,25 +256,26 @@ final class UIKitInteropTests: XCTestCase, View { Text("FR2") } } - let workflowView = WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: FR1.self) { - thenProceed(with: FR2.self) - } - } - let exp = ViewHosting.loadView(workflowView).inspection.inspect { workflowLauncher in - XCTAssertThrowsError(try workflowLauncher.view(ViewControllerWrapper.self)) - XCTAssertEqual(try workflowLauncher.find(FR2.self).text().string(), "FR2") + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + } + } } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() - wait(for: [exp], timeout: TestConstant.timeout) + XCTAssertThrowsError(try launcher.view(ViewControllerWrapper.self)) + XCTAssertEqual(try launcher.find(FR2.self).text().string(), "FR2") } } extension UIViewController { func loadOnDevice() { // UIUTest's loadForTesting method does not work because it uses the deprecated `keyWindow` property. - let window = UIApplication.shared.windows.first + let window = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.first?.windows.first window?.removeViewsFromRootViewController() window?.rootViewController = self From 2ab93e989d108beb1d48973b8faac75d8775ffbc Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 08:59:56 -0700 Subject: [PATCH 23/37] [async-swiftui-tests] - Refactored all the example tests - TT --- .../Views/AccountInformationViewTests.swift | 140 +++++++----------- .../Views/ChangePasswordViewTests.swift | 113 ++++++++------ .../Views/ChangeUsernameViewTests.swift | 28 ++-- .../Views/GenericOnboardingViewTests.swift | 44 +++--- .../Views/LoginTests.swift | 58 ++++---- .../Views/MFAViewTests.swift | 61 ++++---- .../Views/MapFeatureOnboardingViewTests.swift | 26 ++-- .../Views/MapFeatureViewTests.swift | 15 +- .../Views/PasswordFieldTests.swift | 74 +++++---- .../ProfileFeatureOnboardingViewTests.swift | 25 ++-- .../QRScannerFeatureOnboardingViewTests.swift | 25 ++-- .../Views/QRScanningViewTests.swift | 24 +-- .../Views/SignUpTests.swift | 33 +++-- .../Views/SwiftCurrentOnboardingTests.swift | 21 ++- .../Views/TermsAndConditionsTests.swift | 67 +++++---- 15 files changed, 385 insertions(+), 369 deletions(-) diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/AccountInformationViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/AccountInformationViewTests.swift index 3466ef6ad..cf4da271b 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/AccountInformationViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/AccountInformationViewTests.swift @@ -34,31 +34,25 @@ final class AccountInformationViewTests: XCTestCase, WorkflowTestingReceiver { private typealias MFAViewWorkflowView = WorkflowLauncher> - func testUpdatedAccountInformationView() throws { - let exp = ViewHosting.loadView(AccountInformationView()).inspection.inspect { view in - XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Email: ") - XCTAssertEqual(try view.find(ViewType.Text.self, skipFound: 1).string(), "SwiftCurrent@wwt.com") + func testUpdatedAccountInformationView() async throws { + let view = try await AccountInformationView().hostAndInspect(with: \.inspection) - XCTAssertEqual(try view.find(ViewType.Text.self, skipFound: 2).string(), "Password: ") - XCTAssertEqual(try view.find(ViewType.SecureField.self).input(), "supersecure") + XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Email: ") + XCTAssertEqual(try view.find(ViewType.Text.self, skipFound: 1).string(), "SwiftCurrent@wwt.com") - XCTAssertEqual(view.findAll(ViewType.Button.self).count, 2) - } - wait(for: [exp], timeout: TestConstant.timeout) + XCTAssertEqual(try view.find(ViewType.Text.self, skipFound: 2).string(), "Password: ") + XCTAssertEqual(try view.find(ViewType.SecureField.self).input(), "supersecure") + + XCTAssertEqual(view.findAll(ViewType.Button.self).count, 2) } - func testAccountInformationCanLaunchUsernameWorkflowAgnostic() throws { + func testAccountInformationCanLaunchUsernameWorkflowAgnostic() async throws { Self.workflowLaunchedData.removeAll() - var accountInformation: InspectableView>! - let exp = ViewHosting.loadView(AccountInformationView()).inspection.inspect { view in - accountInformation = view - XCTAssertFalse(try view.actualView().emailWorkflowLaunched) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssert(try view.actualView().emailWorkflowLaunched) - } - wait(for: [exp], timeout: TestConstant.timeout) - XCTAssertNotNil(accountInformation) + let accountInformation = try await AccountInformationView().hostAndInspect(with: \.inspection) + XCTAssertFalse(try accountInformation.actualView().emailWorkflowLaunched) + XCTAssertNoThrow(try accountInformation.find(ViewType.Button.self).tap()) + XCTAssert(try accountInformation.actualView().emailWorkflowLaunched) waitUntil(Self.workflowTestingData != nil) let data = Self.workflowTestingData @@ -79,49 +73,38 @@ final class AccountInformationViewTests: XCTestCase, WorkflowTestingReceiver { // Complete workflow (Self.workflowTestingData?.orchestrationResponder as? WorkflowViewModel)?.onFinishPublisher.send(.args("new email")) - wait(for: [ - ViewHosting.loadView(try accountInformation.actualView()).inspection.inspect { view in - XCTAssertEqual(try view.actualView().email, "new email") - XCTAssertFalse(try view.actualView().emailWorkflowLaunched) - } - ], timeout: TestConstant.timeout) + let view = try await accountInformation.actualView().hostAndInspect(with: \.inspection) + XCTAssertEqual(try view.actualView().email, "new email") + XCTAssertFalse(try view.actualView().emailWorkflowLaunched) } - func testAccountInformationDoesNotBlowUp_IfUsernameWorkflowReturnsSomethingWEIRD() throws { + func testAccountInformationDoesNotBlowUp_IfUsernameWorkflowReturnsSomethingWEIRD() async throws { class CustomObj { } Self.workflowLaunchedData.removeAll() - var accountInformation: InspectableView>! - var expectedEmail = "starting value" - let exp = ViewHosting.loadView(AccountInformationView()).inspection.inspect { view in - accountInformation = view - expectedEmail = try view.actualView().email - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - } - wait(for: [exp], timeout: TestConstant.timeout) - if Self.workflowTestingData == nil { throw XCTSkip("test data was not created") } + let accountInformation = try await AccountInformationView().hostAndInspect(with: \.inspection) + let expectedEmail = try accountInformation.actualView().email + + XCTAssertNoThrow(try accountInformation.find(ViewType.Button.self).tap()) + + waitUntil(Self.workflowTestingData != nil) + + XCTAssertNotNil(Self.workflowTestingData) (Self.workflowTestingData?.orchestrationResponder as? WorkflowViewModel)?.onFinishPublisher.send(.args(CustomObj())) - wait(for: [ - ViewHosting.loadView(try accountInformation.actualView()).inspection.inspect { view in - XCTAssert(try view.actualView().emailWorkflowLaunched) - XCTAssertEqual(try view.actualView().email, expectedEmail) - } - ].compactMap { $0 }, timeout: TestConstant.timeout) + let view = try await accountInformation.actualView().hostAndInspect(with: \.inspection) + XCTAssert(try view.actualView().emailWorkflowLaunched) + XCTAssertEqual(try view.actualView().email, expectedEmail) } - func testAccountInformationCanLaunchPasswordWorkflowAgnostic() throws { + func testAccountInformationCanLaunchPasswordWorkflowAgnostic() async throws { Self.workflowLaunchedData.removeAll() - var accountInformation: InspectableView>! - let exp = ViewHosting.loadView(AccountInformationView()).inspection.inspect { view in - accountInformation = view - XCTAssertFalse(try view.actualView().passwordWorkflowLaunched) - XCTAssertNoThrow(try view.find(ViewType.Button.self, skipFound: 1).tap()) - XCTAssert(try view.actualView().passwordWorkflowLaunched) - } - wait(for: [exp], timeout: TestConstant.timeout) - XCTAssertNotNil(accountInformation) + let accountInformation = try await AccountInformationView().hostAndInspect(with: \.inspection) + + XCTAssertFalse(try accountInformation.actualView().passwordWorkflowLaunched) + XCTAssertNoThrow(try accountInformation.find(ViewType.Button.self, skipFound: 1).tap()) + XCTAssert(try accountInformation.actualView().passwordWorkflowLaunched) waitUntil(Self.workflowTestingData != nil) let data = Self.workflowTestingData @@ -142,48 +125,39 @@ final class AccountInformationViewTests: XCTestCase, WorkflowTestingReceiver { // Complete workflow (Self.workflowTestingData?.orchestrationResponder as? WorkflowViewModel)?.onFinishPublisher.send(.args("newPassword")) - wait(for: [ - ViewHosting.loadView(try accountInformation.actualView()).inspection.inspect { view in - XCTAssertEqual(try view.actualView().password, "newPassword") - XCTAssertFalse(try view.actualView().passwordWorkflowLaunched) - } - ], timeout: TestConstant.timeout) + let view = try await accountInformation.actualView().hostAndInspect(with: \.inspection) + XCTAssertEqual(try view.actualView().password, "newPassword") + XCTAssertFalse(try view.actualView().passwordWorkflowLaunched) } - func testAccountInformationDoesNotBlowUp_IfPasswordWorkflowReturnsSomethingWEIRD() throws { + func testAccountInformationDoesNotBlowUp_IfPasswordWorkflowReturnsSomethingWEIRD() async throws { class CustomObj { } Self.workflowLaunchedData.removeAll() - var accountInformation: InspectableView>! - var expectedPassword = "starting value" - let exp = ViewHosting.loadView(AccountInformationView()).inspection.inspect { view in - accountInformation = view - expectedPassword = try view.actualView().password - XCTAssertNoThrow(try view.find(ViewType.Button.self, skipFound: 1).tap()) - } - wait(for: [exp], timeout: TestConstant.timeout) - if Self.workflowTestingData == nil { throw XCTSkip("test data was not created") } + let accountInformation = try await AccountInformationView().hostAndInspect(with: \.inspection) + let expectedPassword = try accountInformation.actualView().password + XCTAssertNoThrow(try accountInformation.find(ViewType.Button.self, skipFound: 1).tap()) + + waitUntil(Self.workflowTestingData != nil) + XCTAssertNotNil(Self.workflowTestingData) + (Self.workflowTestingData?.orchestrationResponder as? WorkflowViewModel)?.onFinishPublisher.send(.args(CustomObj())) - wait(for: [ - ViewHosting.loadView(try accountInformation.actualView()).inspection.inspect { view in - XCTAssert(try view.actualView().passwordWorkflowLaunched) - XCTAssertEqual(try view.actualView().password, expectedPassword) - } - ].compactMap { $0 }, timeout: TestConstant.timeout) + let view = try await accountInformation.actualView().hostAndInspect(with: \.inspection) + XCTAssert(try view.actualView().passwordWorkflowLaunched) + XCTAssertEqual(try view.actualView().password, expectedPassword) } - func testAccountInformationCanLaunchBothWorkflows() throws { - let exp = ViewHosting.loadView(AccountInformationView()).inspection.inspect { view in - XCTAssertEqual(view.findAll(MFAViewWorkflowView.self).count, 0) + func testAccountInformationCanLaunchBothWorkflows() async throws { + let view = try await AccountInformationView().hostAndInspect(with: \.inspection) - let firstButton = try view.find(ViewType.Button.self) - let secondButton = try view.find(ViewType.Button.self, skipFound: 1) - XCTAssertNoThrow(try secondButton.tap()) - XCTAssertNoThrow(try firstButton.tap()) + XCTAssertEqual(view.findAll(MFAViewWorkflowView.self).count, 0) - XCTAssertEqual(view.findAll(MFAViewWorkflowView.self).count, 2) - } - wait(for: [exp], timeout: TestConstant.timeout) + let firstButton = try view.find(ViewType.Button.self) + let secondButton = try view.find(ViewType.Button.self, skipFound: 1) + XCTAssertNoThrow(try secondButton.tap()) + XCTAssertNoThrow(try firstButton.tap()) + + XCTAssertEqual(view.findAll(MFAViewWorkflowView.self).count, 2) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ChangePasswordViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ChangePasswordViewTests.swift index edd5ee5b7..536880901 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ChangePasswordViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ChangePasswordViewTests.swift @@ -14,80 +14,97 @@ import SwiftUI @testable import SwiftUIExample final class ChangePasswordViewTests: XCTestCase, View { - func testChangePasswordView() throws { + func testChangePasswordView() async throws { let currentPassword = UUID().uuidString - let exp = ViewHosting.loadView(ChangePasswordView(with: currentPassword)).inspection.inspect { view in - XCTAssertEqual(view.findAll(PasswordField.self).count, 3) - XCTAssertNoThrow(try view.find(ViewType.Button.self)) + let view = try await MainActor.run { + ChangePasswordView(with: currentPassword) } - wait(for: [exp], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + + XCTAssertEqual(view.findAll(PasswordField.self).count, 3) + XCTAssertNoThrow(try view.find(ViewType.Button.self)) } - func testChangePasswordProceeds_IfAllInformationIsCorrect() throws { + func testChangePasswordProceeds_IfAllInformationIsCorrect() async throws { let currentPassword = UUID().uuidString let onFinish = expectation(description: "onFinish called") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true), startingArgs: currentPassword) { - thenProceed(with: ChangePasswordView.self) - } - .onFinish { _ in onFinish.fulfill() }).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.SecureField.self).setInput(currentPassword)) - XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput("asdfF1")) - XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 2).setInput("asdfF1")) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + let view = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: currentPassword) { + thenProceed(with: ChangePasswordView.self) + } + .onFinish { _ in onFinish.fulfill() } } - wait(for: [exp, onFinish], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + XCTAssertNoThrow(try view.find(ViewType.SecureField.self).setInput(currentPassword)) + XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput("asdfF1")) + XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 2).setInput("asdfF1")) + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + + wait(for: [onFinish], timeout: TestConstant.timeout) } - func testErrorsDoNotShowUp_IfFormWasNotSubmitted() throws { + func testErrorsDoNotShowUp_IfFormWasNotSubmitted() async throws { let currentPassword = UUID().uuidString - let exp = ViewHosting.loadView(ChangePasswordView(with: currentPassword)).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.SecureField.self).setInput(currentPassword)) - XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput("asdfF1")) - XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 2).setInput("asdfF1")) - XCTAssertNoThrow(try view.find(ViewType.Button.self)) + let view = try await MainActor.run { + ChangePasswordView(with: currentPassword) } - wait(for: [exp], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try view.find(ViewType.SecureField.self).setInput(currentPassword)) + XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput("asdfF1")) + XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 2).setInput("asdfF1")) + XCTAssertNoThrow(try view.find(ViewType.Button.self)) } - func testIncorrectOldPassword_PrintsError() throws { + func testIncorrectOldPassword_PrintsError() async throws { let currentPassword = UUID().uuidString - let exp = ViewHosting.loadView(ChangePasswordView(with: currentPassword)).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.SecureField.self).setInput("WRONG")) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssert(try view.vStack().text(0).string().contains("Old password does not match records")) + let view = try await MainActor.run { + ChangePasswordView(with: currentPassword) } - wait(for: [exp], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try view.find(ViewType.SecureField.self).setInput("WRONG")) + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + XCTAssert(try view.vStack().text(0).string().contains("Old password does not match records")) } - func testPasswordsNotMatching_PrintsError() throws { + func testPasswordsNotMatching_PrintsError() async throws { let currentPassword = UUID().uuidString - let exp = ViewHosting.loadView(ChangePasswordView(with: currentPassword)).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.SecureField.self).setInput(currentPassword)) - XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput(UUID().uuidString)) - XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 2).setInput(UUID().uuidString)) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssert(try view.vStack().text(0).string().contains("New password and confirmation password do not match")) + let view = try await MainActor.run { + ChangePasswordView(with: currentPassword) } - wait(for: [exp], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try view.find(ViewType.SecureField.self).setInput(currentPassword)) + XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput(UUID().uuidString)) + XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 2).setInput(UUID().uuidString)) + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + XCTAssert(try view.vStack().text(0).string().contains("New password and confirmation password do not match")) } - func testPasswordsNotHavingUppercase_PrintsError() throws { + func testPasswordsNotHavingUppercase_PrintsError() async throws { let currentPassword = UUID().uuidString - let exp = ViewHosting.loadView(ChangePasswordView(with: currentPassword)).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput("asdf1")) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssert(try view.vStack().text(0).string().contains("Password must contain at least one uppercase character")) + let view = try await MainActor.run { + ChangePasswordView(with: currentPassword) } - wait(for: [exp], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput("asdf1")) + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + XCTAssert(try view.vStack().text(0).string().contains("Password must contain at least one uppercase character")) } - func testPasswordsNotHavingNumber_PrintsError() throws { + func testPasswordsNotHavingNumber_PrintsError() async throws { let currentPassword = UUID().uuidString - let exp = ViewHosting.loadView(ChangePasswordView(with: currentPassword)).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput("asdfF")) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssert(try view.vStack().text(0).string().contains("Password must contain at least one number")) + let view = try await MainActor.run { + ChangePasswordView(with: currentPassword) } - wait(for: [exp], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try view.find(ViewType.SecureField.self, skipFound: 1).setInput("asdfF")) + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + XCTAssert(try view.vStack().text(0).string().contains("Password must contain at least one number")) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ChangeUsernameViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ChangeUsernameViewTests.swift index 1d9bd543d..e938d4ddc 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ChangeUsernameViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ChangeUsernameViewTests.swift @@ -13,17 +13,16 @@ import ViewInspector @testable import SwiftUIExample final class ChangeUsernameViewTests: XCTestCase { - func testChangeUsernameView() throws { + func testChangeUsernameView() async throws { let currentUsername = UUID().uuidString - let exp = ViewHosting.loadView(ChangeEmailView(with: currentUsername)).inspection.inspect { view in - XCTAssertEqual(try view.find(ViewType.Text.self, traversal: .depthFirst).string(), "New email: ") - XCTAssertEqual(try view.find(ViewType.TextField.self).labelView().text().string(), "\(currentUsername)") - XCTAssertNoThrow(try view.find(ViewType.Button.self)) - } - wait(for: [exp], timeout: TestConstant.timeout) + let view = try await ChangeEmailView(with: currentUsername).hostAndInspect(with: \.inspection) + + XCTAssertEqual(try view.find(ViewType.Text.self, traversal: .depthFirst).string(), "New email: ") + XCTAssertEqual(try view.find(ViewType.TextField.self).labelView().text().string(), "\(currentUsername)") + XCTAssertNoThrow(try view.find(ViewType.Button.self)) } - func testChangeUsernameViewProceedsWithCorrectDataWhenNameChanged() { + func testChangeUsernameViewProceedsWithCorrectDataWhenNameChanged() async throws { let newUsername = UUID().uuidString let proceedCalled = expectation(description: "Proceed called") let erased = AnyFlowRepresentableView(type: ChangeEmailView.self, args: .args("")) @@ -34,11 +33,12 @@ final class ChangeUsernameViewTests: XCTestCase { proceedCalled.fulfill() } changeUsernameView._workflowPointer = erased - let exp = ViewHosting.loadView(changeUsernameView).inspection.inspect { view in - XCTAssertEqual(try view.find(ViewType.Text.self, traversal: .depthFirst).string(), "New email: ") - XCTAssertNoThrow(try view.find(ViewType.TextField.self).setInput(newUsername)) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - } - wait(for: [exp, proceedCalled], timeout: TestConstant.timeout) + let view = try await changeUsernameView.hostAndInspect(with: \.inspection) + + XCTAssertEqual(try view.find(ViewType.Text.self, traversal: .depthFirst).string(), "New email: ") + XCTAssertNoThrow(try view.find(ViewType.TextField.self).setInput(newUsername)) + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + + wait(for: [proceedCalled], timeout: TestConstant.timeout) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/GenericOnboardingViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/GenericOnboardingViewTests.swift index 360abe6d9..803a512e8 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/GenericOnboardingViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/GenericOnboardingViewTests.swift @@ -26,21 +26,26 @@ final class GenericOnboardingViewTests: XCTestCase, View { Container.default.removeAll() } - func testOnboardingInWorkflow() throws { + func testOnboardingInWorkflow() async throws { let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) defaults.set(false, forKey: defaultModel.appStorageKey) Container.default.register(UserDefaults.self) { _ in defaults } let workflowFinished = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true), startingArgs: defaultModel) { - thenProceed(with: GenericOnboardingView.self) - }.onFinish { _ in - workflowFinished.fulfill() - }).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Text.self)) - XCTAssertEqual(try view.find(ViewType.Text.self).string(), self.defaultModel.featureTitle) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true), startingArgs: defaultModel) { + thenProceed(with: GenericOnboardingView.self) + }.onFinish { _ in + workflowFinished.fulfill() + } } - wait(for: [exp, workflowFinished], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + XCTAssertNoThrow(try launcher.find(ViewType.Text.self)) + XCTAssertEqual(try launcher.find(ViewType.Text.self).string(), self.defaultModel.featureTitle) + XCTAssertNoThrow(try launcher.find(ViewType.Button.self).tap()) + + wait(for: [workflowFinished], timeout: TestConstant.timeout) } func testOnboardingViewLoads_WhenNoValueIsInUserDefaults() throws { @@ -64,22 +69,23 @@ final class GenericOnboardingViewTests: XCTestCase, View { XCTAssertFalse(GenericOnboardingView(with: defaultModel).shouldLoad(), "Profile onboarding should not show if default is true") } - func testOnboardingAsView() throws { + func testOnboardingAsView() async throws { let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) defaults.set(true, forKey: defaultModel.appStorageKey) Container.default.register(UserDefaults.self) { _ in defaults } let onboardingActionExpectation = expectation(description: "View Proceeded") - let genericOnboardingView = GenericOnboardingView(model: defaultModel) { - onboardingActionExpectation.fulfill() + let onboarding = try await MainActor.run { + GenericOnboardingView(model: defaultModel) { + onboardingActionExpectation.fulfill() + } } + .hostAndInspect(with: \.inspection) - let exp = ViewHosting.loadView(genericOnboardingView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Text.self)) - XCTAssertEqual(try view.find(ViewType.Text.self).string(), self.defaultModel.featureTitle) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - } + XCTAssertNoThrow(try onboarding.find(ViewType.Text.self)) + XCTAssertEqual(try onboarding.find(ViewType.Text.self).string(), self.defaultModel.featureTitle) + XCTAssertNoThrow(try onboarding.find(ViewType.Button.self).tap()) - wait(for: [exp, onboardingActionExpectation], timeout: TestConstant.timeout) + wait(for: [onboardingActionExpectation], timeout: TestConstant.timeout) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/LoginTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/LoginTests.swift index f095aa79b..0af34dc1b 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/LoginTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/LoginTests.swift @@ -28,40 +28,39 @@ final class LoginTests: XCTestCase, View, WorkflowTestingReceiver { Self.workflowLaunchedData.removeAll() } - func testBasicLayout() { - let exp = ViewHosting.loadView(LoginView()).inspection.inspect { view in - XCTAssertEqual(view.findAll(ViewType.TextField.self).count, 1) - XCTAssertEqual(view.findAll(ViewType.SecureField.self).count, 1) - XCTAssertNoThrow(try view.findLoginButton()) - XCTAssertNoThrow(try view.findSignUpButton()) - } - wait(for: [exp], timeout: TestConstant.timeout) + func testBasicLayout() async throws { + let view = try await LoginView().hostAndInspect(with: \.inspection) + + XCTAssertEqual(view.findAll(ViewType.TextField.self).count, 1) + XCTAssertEqual(view.findAll(ViewType.SecureField.self).count, 1) + XCTAssertNoThrow(try view.findLoginButton()) + XCTAssertNoThrow(try view.findSignUpButton()) } - func testLoginProceedsWorkflow() { + func testLoginProceedsWorkflow() async throws { let workflowFinished = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: LoginView.self) - }.onFinish { _ in - workflowFinished.fulfill() - }).inspection.inspect { view in - XCTAssertNoThrow(try view.findLoginButton().tap()) + let view = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: LoginView.self) + }.onFinish { _ in + workflowFinished.fulfill() + } } - wait(for: [exp, workflowFinished], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + XCTAssertNoThrow(try view.findLoginButton().tap()) + + wait(for: [workflowFinished], timeout: TestConstant.timeout) } - func testSignupCorrectlyLaunchesSignupWorkflow() throws { + func testSignupCorrectlyLaunchesSignupWorkflow() async throws { Self.workflowLaunchedData.removeAll() - var loginView: InspectableView>! - let exp = ViewHosting.loadView(LoginView()).inspection.inspect { view in - loginView = view - XCTAssertFalse(try view.actualView().showSignUp) - XCTAssertNoThrow(try view.findSignUpButton().tap()) - XCTAssert(try view.actualView().showSignUp) - } - wait(for: [exp], timeout: TestConstant.timeout) + let loginView = try await LoginView().hostAndInspect(with: \.inspection) - XCTAssertNotNil(loginView) + XCTAssertFalse(try loginView.actualView().showSignUp) + XCTAssertNoThrow(try loginView.findSignUpButton().tap()) + XCTAssert(try loginView.actualView().showSignUp) waitUntil(Self.workflowTestingData != nil) let data = Self.workflowTestingData @@ -76,11 +75,8 @@ final class LoginTests: XCTestCase, View, WorkflowTestingReceiver { // Complete workflow (Self.workflowTestingData?.orchestrationResponder as? WorkflowViewModel)?.onFinishPublisher.send(AnyWorkflow.PassedArgs.none) - wait(for: [ - ViewHosting.loadView(try loginView.actualView()).inspection.inspect { view in - XCTAssertFalse(try view.actualView().showSignUp) - } - ], timeout: TestConstant.timeout) + let view = try await loginView.actualView().hostAndInspect(with: \.inspection) + XCTAssertFalse(try view.actualView().showSignUp) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MFAViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MFAViewTests.swift index 7c91175db..acf6d0f28 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MFAViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MFAViewTests.swift @@ -13,36 +13,33 @@ import ViewInspector @testable import SwiftUIExample final class MFAViewTests: XCTestCase { - func testMFAView() throws { - let exp = ViewHosting.loadView(MFAView(with: .none)).inspection.inspect { view in - XCTAssertEqual(try view.find(ViewType.Text.self, traversal: .depthFirst).string(), - "This is your friendly MFA Assistant! Tap the button below to pretend to send a push notification and require an account code") - XCTAssertEqual(try view.find(ViewType.Button.self).labelView().text().string(), "Start MFA") - } - wait(for: [exp], timeout: TestConstant.timeout) + func testMFAView() async throws { + let view = try await MFAView(with: .none).hostAndInspect(with: \.inspection) + + XCTAssertEqual(try view.find(ViewType.Text.self, traversal: .depthFirst).string(), + "This is your friendly MFA Assistant! Tap the button below to pretend to send a push notification and require an account code") + XCTAssertEqual(try view.find(ViewType.Button.self).labelView().text().string(), "Start MFA") } - func testMFAViewAllowsCodeInput() throws { - let exp = ViewHosting.loadView(MFAView(with: .none)).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Code (enter 1234 to proceed)") - XCTAssertNoThrow(try view.find(ViewType.TextField.self).setInput("1111")) - } - wait(for: [exp], timeout: TestConstant.timeout) + func testMFAViewAllowsCodeInput() async throws { + let view = try await MFAView(with: .none).hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Code (enter 1234 to proceed)") + XCTAssertNoThrow(try view.find(ViewType.TextField.self).setInput("1111")) } - func testMFAViewShowsAlertWhenCodeIsWrong() throws { - let exp = ViewHosting.loadView(MFAView(with: .none)).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Code (enter 1234 to proceed)") - XCTAssertNoThrow(try view.find(ViewType.TextField.self).setInput("1111")) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssertEqual(try view.find(ViewType.Alert.self).title().string(), "Invalid code entered, abandoning workflow.") - } - wait(for: [exp], timeout: TestConstant.timeout) + func testMFAViewShowsAlertWhenCodeIsWrong() async throws { + let view = try await MFAView(with: .none).hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Code (enter 1234 to proceed)") + XCTAssertNoThrow(try view.find(ViewType.TextField.self).setInput("1111")) + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + XCTAssertEqual(try view.find(ViewType.Alert.self).title().string(), "Invalid code entered, abandoning workflow.") } - func testMFAViewViewProceedsWithCorrectDataWhenCorrectMFACodeEntered() { + func testMFAViewViewProceedsWithCorrectDataWhenCorrectMFACodeEntered() async throws { class CustomObj { } let ref = CustomObj() let proceedCalled = expectation(description: "Proceed called") @@ -54,12 +51,14 @@ final class MFAViewTests: XCTestCase { proceedCalled.fulfill() } mfaView._workflowPointer = erased - let exp = ViewHosting.loadView(mfaView).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Code (enter 1234 to proceed)") - XCTAssertNoThrow(try view.find(ViewType.TextField.self).setInput("1234")) - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - } - wait(for: [exp, proceedCalled], timeout: TestConstant.timeout) + + let view = try await mfaView.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Code (enter 1234 to proceed)") + XCTAssertNoThrow(try view.find(ViewType.TextField.self).setInput("1234")) + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + + wait(for: [proceedCalled], timeout: TestConstant.timeout) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MapFeatureOnboardingViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MapFeatureOnboardingViewTests.swift index 93009de85..b54cca0f7 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MapFeatureOnboardingViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MapFeatureOnboardingViewTests.swift @@ -20,21 +20,27 @@ final class MapFeatureOnboardingViewTests: XCTestCase, View { Container.default.removeAll() } - func testOnboardingInWorkflow() throws { + func testOnboardingInWorkflow() async throws { let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) defaults.set(false, forKey: defaultsKey) Container.default.register(UserDefaults.self) { _ in defaults } let workflowFinished = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: MapFeatureOnboardingView.self) - }.onFinish { _ in - workflowFinished.fulfill() - }).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Text.self)) - XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Learn about our awesome map feature!") - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + + let view = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: MapFeatureOnboardingView.self) + }.onFinish { _ in + workflowFinished.fulfill() + } } - wait(for: [exp, workflowFinished], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + XCTAssertNoThrow(try view.find(ViewType.Text.self)) + XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Learn about our awesome map feature!") + XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + + wait(for: [workflowFinished], timeout: TestConstant.timeout) } func testOnboardingViewLoads_WhenNoValueIsInUserDefaults() throws { diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MapFeatureViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MapFeatureViewTests.swift index dd54456b9..b5097af0b 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MapFeatureViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/MapFeatureViewTests.swift @@ -12,13 +12,12 @@ import ViewInspector @testable import SwiftUIExample final class MapFeatureViewTests: XCTestCase { - func testMapFeatureView() throws { - let exp = ViewHosting.loadView(MapFeatureView()).inspection.inspect { view in - let map = try view.map() - let region = try map.coordinateRegion() - XCTAssertEqual(region.center.latitude, 38.70196, accuracy: 0.9) // swiftlint:disable:this number_separator - XCTAssertEqual(region.center.longitude, -90.44906, accuracy: 0.9) // swiftlint:disable:this number_separator - } - wait(for: [exp], timeout: TestConstant.timeout) + func testMapFeatureView() async throws { + let view = try await MapFeatureView().hostAndInspect(with: \.inspection) + + let map = try view.map() + let region = try map.coordinateRegion() + XCTAssertEqual(region.center.latitude, 38.70196, accuracy: 0.9) // swiftlint:disable:this number_separator + XCTAssertEqual(region.center.longitude, -90.44906, accuracy: 0.9) // swiftlint:disable:this number_separator } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/PasswordFieldTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/PasswordFieldTests.swift index 581c87b92..4d1206048 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/PasswordFieldTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/PasswordFieldTests.swift @@ -13,53 +13,45 @@ import ViewInspector @testable import SwiftUIExample class PasswordFieldTests: XCTestCase { - func testRevealButtonTogglesLayout() { - let passwordField = PasswordField(password: Binding(wrappedValue: "")) + func testRevealButtonTogglesLayout() async throws { + let passwordField = try await PasswordField(password: Binding(wrappedValue: "")).hostAndInspect(with: \.inspection) - let exp = ViewHosting.loadView(passwordField).inspection.inspect { view in - XCTAssertEqual(view.findAll(ViewType.Button.self).count, 1) - XCTAssertEqual(view.findAll(ViewType.TextField.self).count, 0) - XCTAssertEqual(view.findAll(ViewType.SecureField.self).count, 1) + XCTAssertEqual(passwordField.findAll(ViewType.Button.self).count, 1) + XCTAssertEqual(passwordField.findAll(ViewType.TextField.self).count, 0) + XCTAssertEqual(passwordField.findAll(ViewType.SecureField.self).count, 1) - try view.find(ViewType.Button.self).tap() - XCTAssertEqual(view.findAll(ViewType.TextField.self).count, 1) - XCTAssertEqual(view.findAll(ViewType.SecureField.self).count, 0) + try passwordField.find(ViewType.Button.self).tap() + XCTAssertEqual(passwordField.findAll(ViewType.TextField.self).count, 1) + XCTAssertEqual(passwordField.findAll(ViewType.SecureField.self).count, 0) - try view.find(ViewType.Button.self).tap() - XCTAssertEqual(view.findAll(ViewType.TextField.self).count, 0) - XCTAssertEqual(view.findAll(ViewType.SecureField.self).count, 1) - } - - wait(for: [exp], timeout: TestConstant.timeout) + try passwordField.find(ViewType.Button.self).tap() + XCTAssertEqual(passwordField.findAll(ViewType.TextField.self).count, 0) + XCTAssertEqual(passwordField.findAll(ViewType.SecureField.self).count, 1) } - func testPasswordIsBoundBetweenStates() { + func testPasswordIsBoundBetweenStates() async throws { let password = Binding(wrappedValue: "initial password") let expectedPassword = "This is the updated password" - let passwordField = PasswordField(showPassword: true, password: password) - - let exp = ViewHosting.loadView(passwordField).inspection.inspect { view in - let textField = try view.find(ViewType.TextField.self) - XCTAssertEqual(try textField.input(), try view.actualView().password) - XCTAssertEqual(password.wrappedValue, try view.actualView().password) - - try textField.setInput(expectedPassword) - XCTAssertEqual(try textField.input(), expectedPassword) - XCTAssertEqual(try view.actualView().password, expectedPassword) - XCTAssertEqual(password.wrappedValue, expectedPassword) - - try view.find(ViewType.Button.self).tap() - let secureField = try view.find(ViewType.SecureField.self) - XCTAssertEqual(try secureField.input(), try view.actualView().password) - XCTAssertEqual(try view.actualView().password, expectedPassword) - XCTAssertEqual(password.wrappedValue, expectedPassword) - - try secureField.setInput("") - XCTAssertEqual(try secureField.input(), "") - XCTAssertEqual(try view.actualView().password, "") - XCTAssertEqual(password.wrappedValue, "") - } - - wait(for: [exp], timeout: TestConstant.timeout) + let passwordField = try await PasswordField(showPassword: true, password: password).hostAndInspect(with: \.inspection) + + let textField = try passwordField.find(ViewType.TextField.self) + XCTAssertEqual(try textField.input(), try passwordField.actualView().password) + XCTAssertEqual(password.wrappedValue, try passwordField.actualView().password) + + try textField.setInput(expectedPassword) + XCTAssertEqual(try textField.input(), expectedPassword) + XCTAssertEqual(try passwordField.actualView().password, expectedPassword) + XCTAssertEqual(password.wrappedValue, expectedPassword) + + try passwordField.find(ViewType.Button.self).tap() + let secureField = try passwordField.find(ViewType.SecureField.self) + XCTAssertEqual(try secureField.input(), try passwordField.actualView().password) + XCTAssertEqual(try passwordField.actualView().password, expectedPassword) + XCTAssertEqual(password.wrappedValue, expectedPassword) + + try secureField.setInput("") + XCTAssertEqual(try secureField.input(), "") + XCTAssertEqual(try passwordField.actualView().password, "") + XCTAssertEqual(password.wrappedValue, "") } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ProfileFeatureOnboardingViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ProfileFeatureOnboardingViewTests.swift index f95c07413..6fd8ae3c7 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ProfileFeatureOnboardingViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ProfileFeatureOnboardingViewTests.swift @@ -20,21 +20,24 @@ final class ProfileFeatureOnboardingViewTests: XCTestCase, View { Container.default.removeAll() } - func testOnboardingInWorkflow() throws { + func testOnboardingInWorkflow() async throws { let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) defaults.set(false, forKey: defaultsKey) Container.default.register(UserDefaults.self) { _ in defaults } let workflowFinished = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: ProfileFeatureOnboardingView.self) - }.onFinish { _ in - workflowFinished.fulfill() - }).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Text.self)) - XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Welcome to our new profile management feature!") - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) - } - wait(for: [exp, workflowFinished], timeout: TestConstant.timeout) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: ProfileFeatureOnboardingView.self) + }.onFinish { _ in + workflowFinished.fulfill() + } + }.hostAndInspect(with: \.inspection) + + XCTAssertNoThrow(try launcher.find(ViewType.Text.self)) + XCTAssertEqual(try launcher.find(ViewType.Text.self).string(), "Welcome to our new profile management feature!") + XCTAssertNoThrow(try launcher.find(ViewType.Button.self).tap()) + + wait(for: [workflowFinished], timeout: TestConstant.timeout) } func testOnboardingViewLoads_WhenNoValueIsInUserDefaults() throws { diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/QRScannerFeatureOnboardingViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/QRScannerFeatureOnboardingViewTests.swift index 31d1d6025..fc2e8c16e 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/QRScannerFeatureOnboardingViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/QRScannerFeatureOnboardingViewTests.swift @@ -20,21 +20,26 @@ final class QRScannerFeatureOnboardingViewTests: XCTestCase, View { Container.default.removeAll() } - func testOnboardingInWorkflow() throws { + func testOnboardingInWorkflow() async throws { let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) defaults.set(false, forKey: defaultsKey) Container.default.register(UserDefaults.self) { _ in defaults } let workflowFinished = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: QRScannerFeatureOnboardingView.self) - }.onFinish { _ in - workflowFinished.fulfill() - }).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Text.self)) - XCTAssertEqual(try view.find(ViewType.Text.self).string(), "Learn about our awesome QR scanning feature!") - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: QRScannerFeatureOnboardingView.self) + }.onFinish { _ in + workflowFinished.fulfill() + } } - wait(for: [exp, workflowFinished], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + XCTAssertNoThrow(try launcher.find(ViewType.Text.self)) + XCTAssertEqual(try launcher.find(ViewType.Text.self).string(), "Learn about our awesome QR scanning feature!") + XCTAssertNoThrow(try launcher.find(ViewType.Button.self).tap()) + + wait(for: [workflowFinished], timeout: TestConstant.timeout) } func testOnboardingViewLoads_WhenNoValueIsInUserDefaults() throws { diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/QRScanningViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/QRScanningViewTests.swift index 13a129ba1..a0ac9b234 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/QRScanningViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/QRScanningViewTests.swift @@ -16,21 +16,23 @@ import CodeScanner @testable import SwiftUIExample final class QRScanningViewTests: XCTestCase { - func testQRScanningView() throws { - let exp = ViewHosting.loadView(QRScannerFeatureView()).inspection.inspect { viewUnderTest in - XCTAssertEqual(try viewUnderTest.view(CodeScannerView.self).actualView().codeTypes, [.qr]) + func testQRScanningView() async throws { + let view = try await QRScannerFeatureView().hostAndInspect(with: \.inspection) + + try await MainActor.run { + XCTAssertEqual(try view.view(CodeScannerView.self).actualView().codeTypes, [.qr]) } - wait(for: [exp], timeout: TestConstant.timeout) } - func testQRScanningView_ShowsSheetWhenScanCompletes() throws { + func testQRScanningView_ShowsSheetWhenScanCompletes() async throws { let code = UUID().uuidString - let exp = ViewHosting.loadView(QRScannerFeatureView()).inspection.inspect { viewUnderTest in - XCTAssertNoThrow(try viewUnderTest.view(CodeScannerView.self).actualView().completion(.success(code))) - XCTAssertEqual(try viewUnderTest.view(CodeScannerView.self).sheet().find(ViewType.Text.self).string(), "SCANNED DATA: \(code)") - XCTAssertNoThrow(try viewUnderTest.view(CodeScannerView.self).sheet().callOnDismiss()) - XCTAssertThrowsError(try viewUnderTest.view(CodeScannerView.self).sheet()) + let view = try await QRScannerFeatureView().hostAndInspect(with: \.inspection) + + try await MainActor.run { + XCTAssertNoThrow(try view.view(CodeScannerView.self).actualView().completion(.success(code))) + XCTAssertEqual(try view.view(CodeScannerView.self).sheet().find(ViewType.Text.self).string(), "SCANNED DATA: \(code)") + XCTAssertNoThrow(try view.view(CodeScannerView.self).sheet().dismiss()) + XCTAssertThrowsError(try view.view(CodeScannerView.self).sheet()) } - wait(for: [exp], timeout: TestConstant.timeout) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/SignUpTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/SignUpTests.swift index 92300fc1f..aa2782896 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/SignUpTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/SignUpTests.swift @@ -14,25 +14,28 @@ import ViewInspector @testable import SwiftUIExample final class SignUpTests: XCTestCase, View { - func testBasicLayout() { - let exp = ViewHosting.loadView(SignUp()).inspection.inspect { view in - XCTAssertEqual(view.findAll(PasswordField.self).count, 2, "2 password fields needed") - XCTAssertEqual(view.findAll(ViewType.TextField.self).count, 1, "1 username field needed") - XCTAssertNoThrow(try view.findProceedButton(), "proceed button needed") - } - wait(for: [exp], timeout: TestConstant.timeout) + func testBasicLayout() async throws { + let view = try await SignUp().hostAndInspect(with: \.inspection) + + XCTAssertEqual(view.findAll(PasswordField.self).count, 2, "2 password fields needed") + XCTAssertEqual(view.findAll(ViewType.TextField.self).count, 1, "1 username field needed") + XCTAssertNoThrow(try view.findProceedButton(), "proceed button needed") } - func testContinueProceedsWorkflow() { + func testContinueProceedsWorkflow() async throws { let workflowFinished = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: SignUp.self) - }.onFinish { _ in - workflowFinished.fulfill() - }).inspection.inspect { view in - XCTAssertNoThrow(try view.findProceedButton().tap()) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: SignUp.self) + }.onFinish { _ in + workflowFinished.fulfill() + } } - wait(for: [exp, workflowFinished], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + XCTAssertNoThrow(try launcher.findProceedButton().tap()) + wait(for: [workflowFinished], timeout: TestConstant.timeout) } } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/SwiftCurrentOnboardingTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/SwiftCurrentOnboardingTests.swift index 7f4698b43..6f0c35c7c 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/SwiftCurrentOnboardingTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/SwiftCurrentOnboardingTests.swift @@ -20,19 +20,24 @@ final class SwiftCurrentOnboardingTests: XCTestCase, View { Container.default.removeAll() } - func testOnboardingInWorkflow() throws { + func testOnboardingInWorkflow() async throws { let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) defaults.set(false, forKey: defaultsKey) Container.default.register(UserDefaults.self) { _ in defaults } let workflowFinished = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: SwiftCurrentOnboarding.self) - }.onFinish { _ in - workflowFinished.fulfill() - }).inspection.inspect { view in - XCTAssertNoThrow(try view.find(ViewType.Button.self).tap()) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: SwiftCurrentOnboarding.self) + }.onFinish { _ in + workflowFinished.fulfill() + } } - wait(for: [exp, workflowFinished], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + XCTAssertNoThrow(try launcher.find(ViewType.Button.self).tap()) + + wait(for: [workflowFinished], timeout: TestConstant.timeout) XCTAssert(defaults.bool(forKey: defaultsKey)) } diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/TermsAndConditionsTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/TermsAndConditionsTests.swift index 436e2e77b..f311999cd 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/TermsAndConditionsTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/TermsAndConditionsTests.swift @@ -14,42 +14,51 @@ import ViewInspector @testable import SwiftUIExample final class TermsAndConditionsTests: XCTestCase, View { - func testLayout() { - let exp = ViewHosting.loadView(TermsAndConditions()).inspection.inspect { view in - XCTAssertEqual(view.findAll(ViewType.Button.self).count, 2) - } - wait(for: [exp], timeout: TestConstant.timeout) + func testLayout() async throws { + let view = try await TermsAndConditions().hostAndInspect(with: \.inspection) + + XCTAssertEqual(view.findAll(ViewType.Button.self).count, 2) } - func testPrimaryAcceptButtonCompletesWorkflow() { + func testPrimaryAcceptButtonCompletesWorkflow() async throws { let workflowFinished = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: TermsAndConditions.self) - }.onAbandon { - XCTFail("Abandon should not have been called") - }.onFinish { _ in - workflowFinished.fulfill() - }).inspection.inspect { view in - let primaryButton = try view.find(PrimaryButton.self) // ToS should have a primary call to accept - XCTAssertEqual(try primaryButton.find(ViewType.Text.self).string(), "Accept") - XCTAssertNoThrow(try primaryButton.find(ViewType.Button.self).tap()) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: TermsAndConditions.self) + }.onAbandon { + XCTFail("Abandon should not have been called") + }.onFinish { _ in + workflowFinished.fulfill() + } } - wait(for: [exp, workflowFinished], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let primaryButton = try launcher.find(PrimaryButton.self) // ToS should have a primary call to accept + XCTAssertEqual(try primaryButton.find(ViewType.Text.self).string(), "Accept") + XCTAssertNoThrow(try primaryButton.find(ViewType.Button.self).tap()) + + wait(for: [workflowFinished], timeout: TestConstant.timeout) } - func testSecondaryRejectButtonAbandonsWorkflow() { + func testSecondaryRejectButtonAbandonsWorkflow() async throws { let workflowAbandoned = expectation(description: "View Proceeded") - let exp = ViewHosting.loadView(WorkflowLauncher(isLaunched: .constant(true)) { - thenProceed(with: TermsAndConditions.self) - }.onAbandon { - workflowAbandoned.fulfill() - }.onFinish { _ in - XCTFail("Complete should not have been called") - }).inspection.inspect { view in - let secondaryButton = try view.find(SecondaryButton.self) // ToS sould have a secondary call to decline - XCTAssertEqual(try secondaryButton.find(ViewType.Text.self).string(), "Decline") - XCTAssertNoThrow(try secondaryButton.find(ViewType.Button.self).tap()) + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: TermsAndConditions.self) + }.onAbandon { + workflowAbandoned.fulfill() + }.onFinish { _ in + XCTFail("Complete should not have been called") + } } - wait(for: [exp, workflowAbandoned], timeout: TestConstant.timeout) + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let secondaryButton = try launcher.find(SecondaryButton.self) // ToS sould have a secondary call to decline + XCTAssertEqual(try secondaryButton.find(ViewType.Text.self).string(), "Decline") + XCTAssertNoThrow(try secondaryButton.find(ViewType.Button.self).tap()) + + wait(for: [workflowAbandoned], timeout: TestConstant.timeout) } } From 52ff0cc6036270d6ab05d1dd9fe77c63320ff9ec Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 09:22:51 -0700 Subject: [PATCH 24/37] [async-swiftui-tests] - Quick fix of warnings - TT --- .../TestUtilities/TopViewController.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ExampleApps/UIKitExample/SwiftCurrent_UIKitTests/TestUtilities/TopViewController.swift b/ExampleApps/UIKitExample/SwiftCurrent_UIKitTests/TestUtilities/TopViewController.swift index 945e2e46d..781755d44 100644 --- a/ExampleApps/UIKitExample/SwiftCurrent_UIKitTests/TestUtilities/TopViewController.swift +++ b/ExampleApps/UIKitExample/SwiftCurrent_UIKitTests/TestUtilities/TopViewController.swift @@ -10,7 +10,11 @@ import Foundation import UIKit extension UIApplication { - static func topViewController(of controller: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? { + static var rootViewController: UIViewController? { + UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.first?.windows.first?.rootViewController + } + + static func topViewController(of controller: UIViewController? = rootViewController) -> UIViewController? { if let navigationController = controller as? UINavigationController, let visible = navigationController.visibleViewController { return topViewController(of: visible) From 34192f2aaae95dde9416a033c4c4e3eab9b8a67a Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 10:40:33 -0700 Subject: [PATCH 25/37] [async-swiftui-tests] - Added a couple more tests - TT --- .../SwiftCurrent_NavigationLinkTests.swift | 201 +++++++++--------- .../SwiftCurrent_SwiftUITests.swift | 2 + .../ViewInspector/ViewHostingExtensions.swift | 78 +++---- 3 files changed, 147 insertions(+), 134 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift index 9bceebcb4..31a01e234 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift @@ -1,102 +1,109 @@ -//// -//// SwiftCurrent_NavigationLinkTests.swift -//// SwiftCurrent -//// -//// Created by Tyler Thompson on 7/12/21. -//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -//// // -//import XCTest -//import SwiftUI -//import ViewInspector +// SwiftCurrent_NavigationLinkTests.swift +// SwiftCurrent // -//import SwiftCurrent -//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work +// Created by Tyler Thompson on 7/12/21. +// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. // -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//final class SwiftCurrent_NavigationLinkTests: XCTestCase, View { -// override func tearDownWithError() throws { -// removeQueuedExpectations() -// } -// -// func testWorkflowCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) -// }.presentationType(.navigationLink) -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertEqual(try fr1.find(FR1.self).text().string(), "FR1 type") -// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssertTrue(try fr1.find(ViewType.NavigationLink.self).isActive()) -// try fr1.find(ViewType.NavigationLink.self).find(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssertEqual(try fr2.find(FR2.self).text().string(), "FR2 type") -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowItemsOfTheSameTypeCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR1.self) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { first in -// XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) -// try first.find(ViewType.NavigationLink.self).view(WorkflowItem, FR1>.self).actualView().inspect(model: model, launcher: launcher) { second in -// XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertFalse(try second.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try second.find(FR1.self).actualView().proceedInWorkflow()) -// try second.actualView().inspect { second in -// XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try second.find(ViewType.NavigationLink.self).isActive()) -// try second.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { third in -// XCTAssertNoThrow(try third.find(FR1.self).actualView().proceedInWorkflow()) -// try third.actualView().inspect { third in -// XCTAssert(try first.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try second.find(ViewType.NavigationLink.self).isActive()) -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + +import XCTest +import SwiftUI +import ViewInspector + +import SwiftCurrent +@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work + +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +final class SwiftCurrent_NavigationLinkTests: XCTestCase, View { + func testWorkflowCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + let expectOnFinish = expectation(description: "OnFinish called") + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) + }.presentationType(.navigationLink) + } + .onFinish { _ in + expectOnFinish.fulfill() + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + XCTAssertEqual(try wfr1.find(FR1.self).text().string(), "FR1 type") + XCTAssertFalse(try wfr1.find(ViewType.NavigationLink.self).isActive()) + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + + // needed to re-host to avoid some kind of race with the nav link + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + + XCTAssertTrue(try wfr1.find(ViewType.NavigationLink.self).isActive()) + XCTAssertEqual(try wfr1.find(FR2.self).text().string(), "FR2 type") + XCTAssertNoThrow(try wfr1.find(FR2.self).actualView().proceedInWorkflow()) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testWorkflowItemsOfTheSameTypeCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR1.self) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + XCTAssertFalse(try wfr1.find(ViewType.NavigationLink.self).isActive()) + XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + + // needed to re-host to avoid some kind of race with the nav link + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + + XCTAssert(try wfr1.find(ViewType.NavigationLink.self).isActive()) + + let wfr2 = try wfr1.findWrapped() + let fr2 = try wfr1.find(ViewType.NavigationLink.self).find(FR1.self) + try await fr2.proceedInWorkflow() + + XCTAssert(try wfr2.find(ViewType.NavigationLink.self).isActive()) + + let wfr3 = try wfr2.findWrapped() + let fr3 = try wfr2.find(ViewType.NavigationLink.self).find(FR1.self) + try await fr3.proceedInWorkflow() + + XCTAssert(try wfr3.find(ViewType.NavigationLink.self).isActive()) + } // // func testLargeWorkflowCanBeFollowed() throws { // struct FR1: View, FlowRepresentable, Inspectable { @@ -407,4 +414,4 @@ // ViewHosting.host(view: launcherView) // wait(for: [expectViewLoaded], timeout: TestConstant.timeout) // } -//} +} diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift index 55cf46630..805944389 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift @@ -411,6 +411,8 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { wait(for: [expectOnAbandon1, expectOnAbandon2], timeout: TestConstant.timeout) } + + #warning("FIXME") // // func testWorkflowCanHaveModifiers() throws { // struct FR1: View, FlowRepresentable, Inspectable { diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index 0565d56af..a0ec3c7f6 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -58,6 +58,10 @@ extension InspectableView where View: CustomViewType & SingleViewContent { } return try await wrapped.inspection.inspect() } + + func findWrapped() throws -> InspectableView, PC>>> where View.T == WorkflowItem, PC> { + try find(View.T.self) + } } @available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) @@ -113,41 +117,41 @@ public extension InspectionEmissary where V: View & Inspectable { @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) extension ViewHosting { - static func loadView(_ view: V) -> V { - defer { - Self.host(view: view) - } - return view - } - - static func loadView(_ view: WorkflowLauncher>) -> WorkflowItem { - var workflowItem: WorkflowItem! - let exp = view.inspection.inspect { - do { - workflowItem = try $0.view(WorkflowItem.self).actualView() - } catch { - XCTFail(error.localizedDescription) - } - } - - Self.host(view: view) - - XCTWaiter().wait(for: [exp], timeout: TestConstant.timeout) - XCTAssertNotNil(workflowItem) - let model = Mirror(reflecting: view).descendant("_model") as? StateObject - let launcher = Mirror(reflecting: view).descendant("_launcher") as? StateObject - XCTAssertNotNil(model) - XCTAssertNotNil(launcher) - defer { - Self.host(view: workflowItem.environmentObject(model!.wrappedValue).environmentObject(launcher!.wrappedValue)) - } - return workflowItem - } - - static func loadView(_ view: WorkflowItem, model: WorkflowViewModel, launcher: Launcher) -> WorkflowItem { - defer { - Self.host(view: view.environmentObject(model).environmentObject(launcher)) - } - return view - } +// static func loadView(_ view: V) -> V { +// defer { +// Self.host(view: view) +// } +// return view +// } +// +// static func loadView(_ view: WorkflowLauncher>) -> WorkflowItem { +// var workflowItem: WorkflowItem! +// let exp = view.inspection.inspect { +// do { +// workflowItem = try $0.view(WorkflowItem.self).actualView() +// } catch { +// XCTFail(error.localizedDescription) +// } +// } +// +// Self.host(view: view) +// +// XCTWaiter().wait(for: [exp], timeout: TestConstant.timeout) +// XCTAssertNotNil(workflowItem) +// let model = Mirror(reflecting: view).descendant("_model") as? StateObject +// let launcher = Mirror(reflecting: view).descendant("_launcher") as? StateObject +// XCTAssertNotNil(model) +// XCTAssertNotNil(launcher) +// defer { +// Self.host(view: workflowItem.environmentObject(model!.wrappedValue).environmentObject(launcher!.wrappedValue)) +// } +// return workflowItem +// } +// +// static func loadView(_ view: WorkflowItem, model: WorkflowViewModel, launcher: Launcher) -> WorkflowItem { +// defer { +// Self.host(view: view.environmentObject(model).environmentObject(launcher)) +// } +// return view +// } } From 925b8df5ef4e3f2f95cf05ee507b209b0399fdd8 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 11:11:01 -0700 Subject: [PATCH 26/37] [async-swiftui-tests] - Huzzah, the tests work for the right reasons, still some nav links to go but the races are solved - TT --- .../SwiftCurrent_NavigationLinkTests.swift | 236 ++++++++---------- .../ViewInspector/ViewHostingExtensions.swift | 4 - 2 files changed, 104 insertions(+), 136 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift index 31a01e234..8051fe16c 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift @@ -47,14 +47,14 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View { XCTAssertEqual(try wfr1.find(FR1.self).text().string(), "FR1 type") XCTAssertFalse(try wfr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR1.self).proceedInWorkflow() // needed to re-host to avoid some kind of race with the nav link try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } XCTAssertTrue(try wfr1.find(ViewType.NavigationLink.self).isActive()) XCTAssertEqual(try wfr1.find(FR2.self).text().string(), "FR2 type") - XCTAssertNoThrow(try wfr1.find(FR2.self).actualView().proceedInWorkflow()) + try await wfr1.find(FR2.self).proceedInWorkflow() wait(for: [expectOnFinish], timeout: TestConstant.timeout) } @@ -85,146 +85,118 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View { } XCTAssertFalse(try wfr1.find(ViewType.NavigationLink.self).isActive()) - XCTAssertNoThrow(try wfr1.find(FR1.self).actualView().proceedInWorkflow()) - + try await wfr1.find(FR1.self).proceedInWorkflow() // needed to re-host to avoid some kind of race with the nav link try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } - XCTAssert(try wfr1.find(ViewType.NavigationLink.self).isActive()) - let wfr2 = try wfr1.findWrapped() - let fr2 = try wfr1.find(ViewType.NavigationLink.self).find(FR1.self) - try await fr2.proceedInWorkflow() - + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertFalse(try wfr2.find(ViewType.NavigationLink.self).isActive()) + try await wfr2.find(FR1.self).proceedInWorkflow() + try await wfr2.actualView().host { $0.environmentObject(model).environmentObject(launcher) } XCTAssert(try wfr2.find(ViewType.NavigationLink.self).isActive()) - let wfr3 = try wfr2.findWrapped() - let fr3 = try wfr2.find(ViewType.NavigationLink.self).find(FR1.self) - try await fr3.proceedInWorkflow() + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + try await wfr3.find(FR1.self).proceedInWorkflow() + } + func testLargeWorkflowCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + struct FR5: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR5 type") } + } + struct FR6: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR6 type") } + } + struct FR7: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR7 type") } + } + + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) { + thenProceed(with: FR5.self) { + thenProceed(with: FR6.self) { + thenProceed(with: FR7.self) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + XCTAssertFalse(try wfr1.find(ViewType.NavigationLink.self).isActive()) + try await wfr1.find(FR1.self).proceedInWorkflow() + // needed to re-host to avoid some kind of race with the nav link + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr1.find(ViewType.NavigationLink.self).isActive()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertFalse(try wfr2.find(ViewType.NavigationLink.self).isActive()) + try await wfr2.find(FR2.self).proceedInWorkflow() + try await wfr2.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr2.find(ViewType.NavigationLink.self).isActive()) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertFalse(try wfr3.find(ViewType.NavigationLink.self).isActive()) + try await wfr3.find(FR3.self).proceedInWorkflow() + try await wfr3.actualView().host { $0.environmentObject(model).environmentObject(launcher) } XCTAssert(try wfr3.find(ViewType.NavigationLink.self).isActive()) + + let wfr4 = try await wfr3.extractWrappedWorkflowItem() + XCTAssertFalse(try wfr4.find(ViewType.NavigationLink.self).isActive()) + try await wfr4.find(FR4.self).proceedInWorkflow() + try await wfr4.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr4.find(ViewType.NavigationLink.self).isActive()) + + let wfr5 = try await wfr4.extractWrappedWorkflowItem() + XCTAssertFalse(try wfr5.find(ViewType.NavigationLink.self).isActive()) + try await wfr5.find(FR5.self).proceedInWorkflow() + try await wfr5.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr5.find(ViewType.NavigationLink.self).isActive()) + + let wfr6 = try await wfr5.extractWrappedWorkflowItem() + XCTAssertFalse(try wfr6.find(ViewType.NavigationLink.self).isActive()) + try await wfr6.find(FR6.self).proceedInWorkflow() + try await wfr6.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr6.find(ViewType.NavigationLink.self).isActive()) + + let wfr7 = try await wfr6.extractWrappedWorkflowItem() + try await wfr7.find(FR7.self).proceedInWorkflow() } // -// func testLargeWorkflowCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// struct FR5: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR5 type") } -// } -// struct FR6: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR6 type") } -// } -// struct FR7: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR7 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) { -// thenProceed(with: FR5.self) { -// thenProceed(with: FR6.self) { -// thenProceed(with: FR7.self) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspect { fr2 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) -// try fr2.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>.self).actualView().inspect(model: model, launcher: launcher) { fr3 in -// XCTAssertFalse(try fr3.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr3.actualView().inspect { fr3 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) -// try fr3.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>, FR4>.self).actualView().inspect(model: model, launcher: launcher) { fr4 in -// XCTAssertFalse(try fr4.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView().proceedInWorkflow()) -// try fr4.actualView().inspect { fr4 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) -// try fr4.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>, FR5>.self).actualView().inspect(model: model, launcher: launcher) { fr5 in -// XCTAssertFalse(try fr5.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr5.find(FR5.self).actualView().proceedInWorkflow()) -// try fr5.actualView().inspect { fr5 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) -// try fr5.find(ViewType.NavigationLink.self).view(WorkflowItem, FR6>.self).actualView().inspect(model: model, launcher: launcher) { fr6 in -// XCTAssertFalse(try fr6.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr6.find(FR6.self).actualView().proceedInWorkflow()) -// try fr6.actualView().inspect { fr6 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr6.find(ViewType.NavigationLink.self).isActive()) -// try fr6.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr7 in -// XCTAssertNoThrow(try fr7.find(FR7.self).actualView().proceedInWorkflow()) -// try fr7.actualView().inspect { fr7 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr3.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr4.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr5.find(ViewType.NavigationLink.self).isActive()) -// XCTAssert(try fr6.find(ViewType.NavigationLink.self).isActive()) -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// // func testNavLinkWorkflowsCanSkipTheFirstItem() throws { // struct FR1: View, FlowRepresentable, Inspectable { // var _workflowPointer: AnyFlowRepresentable? diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index a0ec3c7f6..ff0fc2aee 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -58,10 +58,6 @@ extension InspectableView where View: CustomViewType & SingleViewContent { } return try await wrapped.inspection.inspect() } - - func findWrapped() throws -> InspectableView, PC>>> where View.T == WorkflowItem, PC> { - try find(View.T.self) - } } @available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) From a72ceb7a2bd29b436cc0cf0156a6f51754519321 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 11:27:28 -0700 Subject: [PATCH 27/37] [async-swiftui-tests] - Nav link tests refactored! - TT --- .../SwiftCurrent_NavigationLinkTests.swift | 411 ++++++++++-------- 1 file changed, 221 insertions(+), 190 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift index 8051fe16c..ea792edfc 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_NavigationLinkTests.swift @@ -196,194 +196,225 @@ final class SwiftCurrent_NavigationLinkTests: XCTestCase, View { let wfr7 = try await wfr6.extractWrappedWorkflowItem() try await wfr7.find(FR7.self).proceedInWorkflow() } -// -// func testNavLinkWorkflowsCanSkipTheFirstItem() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertThrowsError(try fr1.find(FR1.self).actualView()) -// try fr1.view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.find(ViewType.NavigationLink.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in -// XCTAssert(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testNavLinkWorkflowsCanSkipOneItemInTheMiddle() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR2>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testNavLinkWorkflowsCanSkipTwoItemsInTheMiddle() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) -// } -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR3>, FR2>.self).view(WorkflowItem, FR3>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr4 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) -// XCTAssertThrowsError(try fr1.find(FR3.self).actualView()) -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView()) -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testNavLinkWorkflowsCanSkipLastItem() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// func shouldLoad() -> Bool { false } -// } -// -// let expectOnFinish = expectation(description: "onFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) -// }.presentationType(.navigationLink) -// }.presentationType(.navigationLink) -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertFalse(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// try fr1.find(ViewType.NavigationLink.self).view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssert(try fr1.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertFalse(try fr2.find(ViewType.NavigationLink.self).isActive()) -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testConvenienceEmbedInNavViewFunction() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// -// let launcherView = WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self).presentationType(.navigationLink) -// }.embedInNavigationView() -// -// let expectViewLoaded = launcherView.inspection.inspect { launcher in -// let navView = try launcher.navigationView() -// XCTAssert(try navView.navigationViewStyle() is StackNavigationViewStyle) -// XCTAssertNoThrow(try navView.view(WorkflowItem.self, 0)) -// } -// ViewHosting.host(view: launcherView) -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } + + func testNavLinkWorkflowsCanSkipTheFirstItem() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + func shouldLoad() -> Bool { false } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + XCTAssertThrowsError(try wfr1.find(FR1.self).actualView()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertFalse(try wfr2.find(ViewType.NavigationLink.self).isActive()) + try await wfr2.find(FR2.self).proceedInWorkflow() + try await wfr2.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr2.find(ViewType.NavigationLink.self).isActive()) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr3.find(FR3.self).actualView()) + } + + func testNavLinkWorkflowsCanSkipOneItemInTheMiddle() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + func shouldLoad() -> Bool { false } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + XCTAssertFalse(try wfr1.find(ViewType.NavigationLink.self).isActive()) + try await wfr1.find(FR1.self).proceedInWorkflow() + // needed to re-host to avoid some kind of race with the nav link + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr1.find(ViewType.NavigationLink.self).isActive()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr2.find(FR2.self)) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr3.find(FR3.self).actualView()) + } + + func testNavLinkWorkflowsCanSkipTwoItemsInTheMiddle() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + func shouldLoad() -> Bool { false } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + func shouldLoad() -> Bool { false } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) + } + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + XCTAssertFalse(try wfr1.find(ViewType.NavigationLink.self).isActive()) + try await wfr1.find(FR1.self).proceedInWorkflow() + // needed to re-host to avoid some kind of race with the nav link + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr1.find(ViewType.NavigationLink.self).isActive()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr2.find(FR2.self)) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr3.find(FR3.self).actualView()) + + let wfr4 = try await wfr3.extractWrappedWorkflowItem() + XCTAssertNoThrow(try wfr4.find(FR4.self).actualView()) + } + + func testNavLinkWorkflowsCanSkipLastItem() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + func shouldLoad() -> Bool { false } + } + + let expectOnFinish = expectation(description: "onFinish called") + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) + }.presentationType(.navigationLink) + }.presentationType(.navigationLink) + } + .onFinish { _ in + expectOnFinish.fulfill() + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + XCTAssertFalse(try wfr1.find(ViewType.NavigationLink.self).isActive()) + try await wfr1.find(FR1.self).proceedInWorkflow() + // needed to re-host to avoid some kind of race with the nav link + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssert(try wfr1.find(ViewType.NavigationLink.self).isActive()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertFalse(try wfr2.find(ViewType.NavigationLink.self).isActive()) + try await wfr2.find(FR2.self).proceedInWorkflow() + try await wfr2.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertFalse(try wfr2.find(ViewType.NavigationLink.self).isActive()) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr3.find(FR3.self)) + XCTAssertNoThrow(try wfr2.find(FR2.self)) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testConvenienceEmbedInNavViewFunction() throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + + let launcherView = WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self).presentationType(.navigationLink) + }.embedInNavigationView() + + let expectViewLoaded = launcherView.inspection.inspect { launcher in + let navView = try launcher.navigationView() + XCTAssert(try navView.navigationViewStyle() is StackNavigationViewStyle) + XCTAssertNoThrow(try navView.view(WorkflowItem.self, 0)) + } + ViewHosting.host(view: launcherView) + wait(for: [expectViewLoaded], timeout: TestConstant.timeout) + } } From 8ea01d2fa234d173bbd7f00d25b23ba6e3d62b10 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 11:31:10 -0700 Subject: [PATCH 28/37] [async-swiftui-tests] - Fixed some of the runtime warnings about executing UI stuff on a background thread - TT --- Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift b/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift index 431647f32..9d9a2e763 100644 --- a/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/PersistenceTests.swift @@ -85,7 +85,7 @@ final class PersistenceTests: XCTestCase, View { try await launcher.find(FR1.self).proceedInWorkflow() try await launcher.find(FR2.self).proceedInWorkflow() - XCTAssertNoThrow(try launcher.find(FR3.self).actualView().backUpInWorkflow()) + try await launcher.find(FR3.self).backUpInWorkflow() try await launcher.find(FR1.self).proceedInWorkflow() try await launcher.find(FR2.self).proceedInWorkflow() @@ -171,7 +171,7 @@ final class PersistenceTests: XCTestCase, View { try await launcher.find(FR1.self).proceedInWorkflow() try await launcher.find(FR2.self).proceedInWorkflow() try await launcher.find(FR3.self).proceedInWorkflow() - XCTAssertNoThrow(try launcher.find(FR4.self).actualView().backUpInWorkflow()) + try await launcher.find(FR4.self).backUpInWorkflow() try await launcher.find(FR1.self).proceedInWorkflow() try await launcher.find(FR2.self).proceedInWorkflow() try await launcher.find(FR3.self).proceedInWorkflow() From d59495796605f4791b26c523354af08f9d638f7a Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 11:33:22 -0700 Subject: [PATCH 29/37] [async-swiftui-tests] - Fixed a bunch of other runtime errors for being on the wrong thread - TT --- .../SwiftCurrent_SwiftUITests.swift | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift index 805944389..24a463cc0 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift @@ -37,7 +37,7 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { }.hostAndInspect(with: \.inspection) XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() let fr2 = try launcher.find(FR2.self) XCTAssertEqual(try fr2.text().string(), "FR2 type") XCTAssertNoThrow(try fr2.actualView().proceedInWorkflow()) @@ -67,7 +67,7 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() wait(for: [expectOnFinish1, expectOnFinish2], timeout: TestConstant.timeout) } @@ -99,20 +99,20 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() await MainActor.run { TestUtils.showWorkflow.wrappedValue = true TestUtils.showWorkflow.update() } - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() await MainActor.run { TestUtils.showWorkflow.wrappedValue = true TestUtils.showWorkflow.update() } - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() wait(for: [expectOnFinish1, expectOnFinish2], timeout: TestConstant.timeout) } @@ -226,11 +226,11 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { }.hostAndInspect(with: \.inspection) XCTAssertEqual(try launcher.find(FR1.self).actualView().property, expectedFR1) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow(expectedFR2)) + try await launcher.find(FR1.self).proceedInWorkflow(expectedFR2) XCTAssertEqual(try launcher.find(FR2.self).actualView().property, expectedFR2) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow(expectedFR3)) + try await launcher.find(FR2.self).proceedInWorkflow(expectedFR3) XCTAssertEqual(try launcher.find(FR3.self).actualView().property, expectedFR3) - XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow(expectedEnd)) + try await launcher.find(FR3.self).proceedInWorkflow(expectedEnd) } func testLargeWorkflowCanBeFollowed() async throws { @@ -281,13 +281,13 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR4.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR5.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR6.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR7.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR4.self).proceedInWorkflow() + try await launcher.find(FR5.self).proceedInWorkflow() + try await launcher.find(FR6.self).proceedInWorkflow() + try await launcher.find(FR7.self).proceedInWorkflow() } func testWorkflowOnlyShowsOneViewAtATime() async throws { @@ -315,10 +315,10 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() XCTAssertThrowsError(try launcher.find(ViewType.Text.self, skipFound: 1)) } @@ -351,14 +351,14 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() XCTAssertNoThrow(try launcher.find(FR2.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() XCTAssertNoThrow(try launcher.find(FR3.self).actualView().backUpInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR4.self).actualView().proceedInWorkflow()) + try await launcher.find(FR2.self).proceedInWorkflow() + try await launcher.find(FR3.self).proceedInWorkflow() + try await launcher.find(FR4.self).proceedInWorkflow() } func testWorkflowSetsBindingBooleanToFalseWhenAbandoned() async throws { @@ -459,7 +459,7 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() await MainActor.run { TestUtils.binding.wrappedValue = false } XCTAssertThrowsError(try launcher.find(FR1.self)) @@ -498,11 +498,11 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { } }.hostAndInspect(with: \.inspection) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() XCTAssertNoThrow(try launcher.find(FR2.self).actualView().abandon()) XCTAssertThrowsError(try launcher.find(FR2.self)) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() + try await launcher.find(FR2.self).proceedInWorkflow() wait(for: [onFinishCalled], timeout: TestConstant.timeout) } @@ -537,9 +537,9 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { }.hostAndInspect(with: \.inspection) XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow(.args(expectedArgs))) + try await launcher.find(FR1.self).proceedInWorkflow(.args(expectedArgs)) XCTAssertEqual(try launcher.find(FR2.self).text().string(), "FR2 type") - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow()) + try await launcher.find(FR2.self).proceedInWorkflow() wait(for: [expectOnFinish], timeout: TestConstant.timeout) } @@ -573,7 +573,7 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") XCTAssertEqual(try launcher.find(FR1.self).actualView().data, expectedArgs) - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() wait(for: [expectOnFinish], timeout: TestConstant.timeout) } @@ -617,11 +617,11 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { }.hostAndInspect(with: \.inspection) XCTAssertEqual(try launcher.find(FR1.self).text().string(), "FR1 type") - XCTAssertNoThrow(try launcher.find(FR1.self).actualView().proceedInWorkflow()) + try await launcher.find(FR1.self).proceedInWorkflow() XCTAssertEqual(try launcher.find(FR2.self).text().string(), "FR2 type") - XCTAssertNoThrow(try launcher.find(FR2.self).actualView().proceedInWorkflow(.args(expectedArgs))) + try await launcher.find(FR2.self).proceedInWorkflow(.args(expectedArgs)) XCTAssertEqual(try launcher.find(FR3.self).text().string(), "FR3 type, \(expectedArgs)") - XCTAssertNoThrow(try launcher.find(FR3.self).actualView().proceedInWorkflow()) + try await launcher.find(FR3.self).proceedInWorkflow() wait(for: [expectOnFinish], timeout: TestConstant.timeout) } From 92aefe32159216ef366f26d98c11fe33ad77ae00 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 11:40:22 -0700 Subject: [PATCH 30/37] [async-swiftui-tests] - ContentView tests back up and running - TT --- .../Views/ContentViewTests.swift | 64 +++++++------------ 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ContentViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ContentViewTests.swift index afdd43558..048eb2bc7 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ContentViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ContentViewTests.swift @@ -22,44 +22,28 @@ final class ContentViewTests: XCTestCase { Container.default.removeAll() } - #warning("FIXME") -// func testContentView() throws { -// let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) -// Container.default.register(UserDefaults.self) { _ in defaults } -// var wf1: MapWorkflow! -// var wf2: QRScannerWorkflow! -// var wf3: ProfileWorkflow! -// let exp = ViewHosting.loadView(ContentView()).inspection.inspect { view in -// wf1 = try view.tabView().view(MapWorkflow.self, 0).actualView() -// XCTAssertEqual(try view.tabView().view(MapWorkflow.self, 0).tabItem().label().title().text().string(), "Map") -// wf2 = try view.tabView().view(QRScannerWorkflow.self, 1).actualView() -// XCTAssertEqual(try view.tabView().view(QRScannerWorkflow.self, 1).tabItem().label().title().text().string(), "QR Scanner") -// wf3 = try view.tabView().view(ProfileWorkflow.self, 2).actualView() -// XCTAssertEqual(try view.tabView().view(ProfileWorkflow.self, 2).tabItem().label().title().text().string(), "Profile") -// } -// wait(for: [exp], timeout: TestConstant.timeout) -// XCTAssertNotNil(wf1) -// XCTAssertNotNil(wf2) -// XCTAssertNotNil(wf3) -// wait(for: [ -// ViewHosting.loadView(wf1).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(MapFeatureOnboardingView.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(MapFeatureView.self)) -// } -// }, -// ViewHosting.loadView(wf2).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(QRScannerFeatureOnboardingView.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(QRScannerFeatureView.self)) -// } -// }, -// ViewHosting.loadView(wf3).inspection.inspect { view in -// XCTAssertNoThrow(try view.find(ProfileFeatureOnboardingView.self).actualView().proceedInWorkflow()) -// try view.actualView().inspectWrapped { view in -// XCTAssertNoThrow(try view.find(ProfileFeatureView.self)) -// } -// } -// ].compactMap { $0 }, timeout: TestConstant.timeout) -// } + func testContentView() async throws { + let defaults = try XCTUnwrap(UserDefaults(suiteName: #function)) + Container.default.register(UserDefaults.self) { _ in defaults } + + let contentView = try await ContentView().hostAndInspect(with: \.inspection) + let wf1 = try contentView.tabView().view(MapWorkflow.self, 0).actualView() + XCTAssertEqual(try contentView.tabView().view(MapWorkflow.self, 0).tabItem().label().title().text().string(), "Map") + let wf2 = try contentView.tabView().view(QRScannerWorkflow.self, 1).actualView() + XCTAssertEqual(try contentView.tabView().view(QRScannerWorkflow.self, 1).tabItem().label().title().text().string(), "QR Scanner") + let wf3 = try contentView.tabView().view(ProfileWorkflow.self, 2).actualView() + XCTAssertEqual(try contentView.tabView().view(ProfileWorkflow.self, 2).tabItem().label().title().text().string(), "Profile") + + let wfr1 = try await wf1.hostAndInspect(with: \.inspection) + try await wfr1.find(MapFeatureOnboardingView.self).proceedInWorkflow() + XCTAssertNoThrow(try wfr1.find(MapFeatureView.self)) + + let wfr2 = try await wf2.hostAndInspect(with: \.inspection) + try await wfr2.find(QRScannerFeatureOnboardingView.self).proceedInWorkflow() + XCTAssertNoThrow(try wfr2.find(QRScannerFeatureView.self)) + + let wfr3 = try await wf3.hostAndInspect(with: \.inspection) + try await wfr3.find(ProfileFeatureOnboardingView.self).proceedInWorkflow() + XCTAssertNoThrow(try wfr3.find(ProfileFeatureView.self)) + } } From 14d2682b3b81164d8e5c54fc755c7b1efb8d0391 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 11:46:28 -0700 Subject: [PATCH 31/37] [async-swiftui-tests] - All old ViewHosting extensions have been replaced, all FIXMEs have been fixed - TT --- .../SwiftCurrent_SwiftUITests.swift | 40 ++++++++---------- .../ViewInspector/ViewHostingExtensions.swift | 41 ------------------- 2 files changed, 18 insertions(+), 63 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift index 24a463cc0..9e2bdd921 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_SwiftUITests.swift @@ -412,28 +412,24 @@ final class SwiftCurrent_SwiftUIConsumerTests: XCTestCase, App { wait(for: [expectOnAbandon1, expectOnAbandon2], timeout: TestConstant.timeout) } - #warning("FIXME") -// -// func testWorkflowCanHaveModifiers() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// -// func customModifier() -> Self { self } -// } -// -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self).applyModifiers { $0.customModifier().background(Color.blue) -// } -// } -// ).inspection.inspect { viewUnderTest in -// XCTAssertNoThrow(try viewUnderTest.find(FR1.self).background()) -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// + func testWorkflowCanHaveModifiers() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + + func customModifier() -> Self { self } + } + + let launcher = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self).applyModifiers { $0.customModifier().padding().onAppear { } } + } + }.hostAndInspect(with: \.inspection) + + XCTAssert(try launcher.find(FR1.self).hasPadding()) + XCTAssertNoThrow(try launcher.find(FR1.self).callOnAppear()) + } + func testWorkflowRelaunchesWhenSubsequentlyLaunched() async throws { throw XCTSkip("We are currently unable to test this because of a limitation in ViewInspector, see here: https://github.com/nalexn/ViewInspector/issues/126") struct FR1: View, FlowRepresentable, Inspectable { diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index ff0fc2aee..a33364805 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -110,44 +110,3 @@ public extension InspectionEmissary where V: View & Inspectable { } } } - -@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -extension ViewHosting { -// static func loadView(_ view: V) -> V { -// defer { -// Self.host(view: view) -// } -// return view -// } -// -// static func loadView(_ view: WorkflowLauncher>) -> WorkflowItem { -// var workflowItem: WorkflowItem! -// let exp = view.inspection.inspect { -// do { -// workflowItem = try $0.view(WorkflowItem.self).actualView() -// } catch { -// XCTFail(error.localizedDescription) -// } -// } -// -// Self.host(view: view) -// -// XCTWaiter().wait(for: [exp], timeout: TestConstant.timeout) -// XCTAssertNotNil(workflowItem) -// let model = Mirror(reflecting: view).descendant("_model") as? StateObject -// let launcher = Mirror(reflecting: view).descendant("_launcher") as? StateObject -// XCTAssertNotNil(model) -// XCTAssertNotNil(launcher) -// defer { -// Self.host(view: workflowItem.environmentObject(model!.wrappedValue).environmentObject(launcher!.wrappedValue)) -// } -// return workflowItem -// } -// -// static func loadView(_ view: WorkflowItem, model: WorkflowViewModel, launcher: Launcher) -> WorkflowItem { -// defer { -// Self.host(view: view.environmentObject(model).environmentObject(launcher)) -// } -// return view -// } -} From 3bcd4a5ba5d38ec0f513d2636c1c08064e691341 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 11:47:32 -0700 Subject: [PATCH 32/37] [async-swiftui-tests] - re-enabled the pipeline - TT --- .github/workflows/PR_CI.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/PR_CI.yml b/.github/workflows/PR_CI.yml index 0d793c1ea..9b2e83bb8 100644 --- a/.github/workflows/PR_CI.yml +++ b/.github/workflows/PR_CI.yml @@ -4,8 +4,7 @@ on: [ pull_request ] jobs: test: - runs-on: macos-12 - if: ${{ false }} # disable for now, until macos-12 because available + runs-on: macos-11 env: working-directory: .github DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer From 7428654cd4220d8dd28725cbcb73e9e18ba90b05 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 11:50:29 -0700 Subject: [PATCH 33/37] [async-swiftui-tests] - Fixed a linter error - TT --- .../Views/ProfileFeatureOnboardingViewTests.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ProfileFeatureOnboardingViewTests.swift b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ProfileFeatureOnboardingViewTests.swift index 6fd8ae3c7..32c7f90da 100644 --- a/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ProfileFeatureOnboardingViewTests.swift +++ b/ExampleApps/SwiftUIExample/SwiftUIExampleTests/Views/ProfileFeatureOnboardingViewTests.swift @@ -31,7 +31,8 @@ final class ProfileFeatureOnboardingViewTests: XCTestCase, View { }.onFinish { _ in workflowFinished.fulfill() } - }.hostAndInspect(with: \.inspection) + } + .hostAndInspect(with: \.inspection) XCTAssertNoThrow(try launcher.find(ViewType.Text.self)) XCTAssertEqual(try launcher.find(ViewType.Text.self).string(), "Welcome to our new profile management feature!") From 5f33d537a6a60ead5c58072642dafbf459741c18 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 12:32:56 -0700 Subject: [PATCH 34/37] [async-swiftui-tests] - Finished refactoring modal tests, that should be everything - TT --- .../SwiftCurrent_ModalTests.swift | 817 +++++++++--------- 1 file changed, 395 insertions(+), 422 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift index 73097c849..f3c65704d 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift @@ -1,423 +1,396 @@ -//// -//// SwiftCurrent_ModalTests.swift -//// SwiftCurrent -//// -//// Created by Tyler Thompson on 7/12/21. -//// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. -//// // -//import XCTest -//import SwiftUI -// -//import SwiftCurrent -// -//@testable import ViewInspector -//@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//extension InspectableView where View == ViewType.Sheet { -// func isPresented() throws -> Bool { -// return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false -// } -//} -// -//@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) -//final class SwiftCurrent_ModalTests: XCTestCase, Scene { -// override func tearDownWithError() throws { -// removeQueuedExpectations() -// } -// -// func testWorkflowCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// let expectOnFinish = expectation(description: "OnFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self).presentationType(.modal) -// } -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertEqual(try fr1.find(FR1.self).text().string(), "FR1 type") -// try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect(model: model, launcher: launcher) { fr1 in -// XCTAssertTrue(try fr1.find(ViewType.Sheet.self).isPresented()) -// try fr1.find(ViewType.Sheet.self).find(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssertEqual(try fr2.view(FR2.self).text().string(), "FR2 type") -// XCTAssertNoThrow(try fr2.view(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testWorkflowItemsOfTheSameTypeCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR1.self).presentationType(.modal) -// }.presentationType(.modal) -// } -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { first in -// XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) -// try first.find(ViewType.Sheet.self).view(WorkflowItem, FR1>.self).actualView().inspect(model: model, launcher: launcher) { second in -// XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) -// XCTAssertNoThrow(try second.find(FR1.self).actualView().proceedInWorkflow()) -// try second.actualView().inspect { second in -// XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) -// try second.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { third in -// XCTAssertNoThrow(try third.find(FR1.self).actualView().proceedInWorkflow()) -// try third.actualView().inspect { third in -// XCTAssert(try first.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try second.find(ViewType.Sheet.self).isPresented()) -// } -// } -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testLargeWorkflowCanBeFollowed() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR4 type") } -// } -// struct FR5: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR5 type") } -// } -// struct FR6: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR6 type") } -// } -// struct FR7: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR7 type") } -// } -// var model: WorkflowViewModel! -// var launcher: Launcher! -// var fr1: InspectableView, FR6>, FR5>, FR4>, FR3>, FR2>, FR1>>>! -// var fr2: InspectableView, FR6>, FR5>, FR4>, FR3>, FR2>>>! -// var fr3: InspectableView, FR6>, FR5>, FR4>, FR3>>>! -// var fr4: InspectableView, FR6>, FR5>, FR4>>>! -// var fr5: InspectableView, FR6>, FR5>>>! -// var fr6: InspectableView, FR6>>>! -// -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self) { -// thenProceed(with: FR5.self) { -// thenProceed(with: FR6.self) { -// thenProceed(with: FR7.self).presentationType(.modal) -// }.presentationType(.modal) -// }.presentationType(.modal) -// }.presentationType(.modal) -// }.presentationType(.modal) -// }.presentationType(.modal) -// } -// } -// ).inspection.inspect { fr_1 in -// model = (Mirror(reflecting: try fr_1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// launcher = (Mirror(reflecting: try fr_1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr_1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr_1.actualView().inspect { fr_1 in -// XCTAssert(try fr_1.find(ViewType.Sheet.self).isPresented()) -// fr1 = fr_1 -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// -// removeQueuedExpectations() -// -// try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr_2 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssertNoThrow(try fr_2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr_2.actualView().inspect { fr_2 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr_2.find(ViewType.Sheet.self).isPresented()) -// fr2 = fr_2 -// } -// } -// -// removeQueuedExpectations() -// -// try fr2.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>, FR3>.self).actualView().inspect(model: model, launcher: launcher) { fr_3 in -// XCTAssertNoThrow(try fr_3.find(FR3.self).actualView().proceedInWorkflow()) -// try fr_3.actualView().inspect { fr_3 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr_3.find(ViewType.Sheet.self).isPresented()) -// fr3 = fr_3 -// } -// } -// -// removeQueuedExpectations() -// -// try fr3.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>, FR4>.self).actualView().inspect(model: model, launcher: launcher) { fr_4 in -// XCTAssertNoThrow(try fr_4.find(FR4.self).actualView().proceedInWorkflow()) -// try fr_4.actualView().inspect { fr_4 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr_4.find(ViewType.Sheet.self).isPresented()) -// fr4 = fr_4 -// } -// } -// -// removeQueuedExpectations() -// -// try fr4.find(ViewType.Sheet.self).view(WorkflowItem, FR6>, FR5>.self).actualView().inspect(model: model, launcher: launcher) { fr_5 in -// XCTAssertNoThrow(try fr_5.find(FR5.self).actualView().proceedInWorkflow()) -// try fr_5.actualView().inspect { fr_5 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr_5.find(ViewType.Sheet.self).isPresented()) -// fr5 = fr_5 -// } -// } -// -// removeQueuedExpectations() -// -// try fr5.find(ViewType.Sheet.self).view(WorkflowItem, FR6>.self).actualView().inspect(model: model, launcher: launcher) { fr_6 in -// XCTAssertNoThrow(try fr_6.find(FR6.self).actualView().proceedInWorkflow()) -// try fr_6.actualView().inspect { fr_6 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr5.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr_6.find(ViewType.Sheet.self).isPresented()) -// fr6 = fr_6 -// } -// } -// -// removeQueuedExpectations() -// -// try fr6.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr7 in -// XCTAssertNoThrow(try fr7.find(FR7.self).actualView().proceedInWorkflow()) -// try fr7.actualView().inspect { fr7 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr3.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr4.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr5.find(ViewType.Sheet.self).isPresented()) -// XCTAssert(try fr6.find(ViewType.Sheet.self).isPresented()) -// } -// } -// } -// -// func testNavLinkWorkflowsCanSkipTheFirstItem() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self).presentationType(.modal) -// }.presentationType(.modal) -// } -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertThrowsError(try fr1.find(FR1.self).actualView()) -// try fr1.view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// try fr2.actualView().inspect { fr2 in -// try fr2.find(ViewType.Sheet.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in -// XCTAssert(try fr2.find(ViewType.Sheet.self).isPresented()) -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) -// } -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testNavLinkWorkflowsCanSkipOneItemInTheMiddle() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self).presentationType(.modal) -// }.presentationType(.modal) -// } -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr3 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) -// XCTAssertNoThrow(try fr3.find(FR3.self).actualView()) -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testNavLinkWorkflowsCanSkipTwoItemsInTheMiddle() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// func shouldLoad() -> Bool { false } -// } -// struct FR4: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// } -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self) { -// thenProceed(with: FR4.self).presentationType(.modal) -// } -// }.presentationType(.modal) -// } -// } -// ).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR3>, FR2>.self).view(WorkflowItem, FR3>.self).view(WorkflowItem.self).actualView().inspect(model: model, launcher: launcher) { fr4 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssertThrowsError(try fr1.find(FR2.self).actualView()) -// XCTAssertThrowsError(try fr1.find(FR3.self).actualView()) -// XCTAssertNoThrow(try fr4.find(FR4.self).actualView()) -// } -// } -// } -// -// wait(for: [expectViewLoaded], timeout: TestConstant.timeout) -// } -// -// func testNavLinkWorkflowsCanSkipLastItem() throws { -// struct FR1: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR1 type") } -// } -// struct FR2: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR2 type") } -// } -// struct FR3: View, FlowRepresentable, Inspectable { -// var _workflowPointer: AnyFlowRepresentable? -// var body: some View { Text("FR3 type") } -// func shouldLoad() -> Bool { false } -// } -// -// let expectOnFinish = expectation(description: "onFinish called") -// let expectViewLoaded = ViewHosting.loadView( -// WorkflowLauncher(isLaunched: .constant(true)) { -// thenProceed(with: FR1.self) { -// thenProceed(with: FR2.self) { -// thenProceed(with: FR3.self).presentationType(.modal) -// }.presentationType(.modal) -// } -// } -// .onFinish { _ in -// expectOnFinish.fulfill() -// }).inspection.inspect { fr1 in -// let model = (Mirror(reflecting: try fr1.actualView()).descendant("_model") as! EnvironmentObject).wrappedValue -// let launcher = (Mirror(reflecting: try fr1.actualView()).descendant("_launcher") as! EnvironmentObject).wrappedValue -// XCTAssertNoThrow(try fr1.find(FR1.self).actualView().proceedInWorkflow()) -// try fr1.actualView().inspect { fr1 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// try fr1.find(ViewType.Sheet.self).view(WorkflowItem, FR2>.self).actualView().inspect(model: model, launcher: launcher) { fr2 in -// XCTAssert(try fr1.find(ViewType.Sheet.self).isPresented()) -// XCTAssertNoThrow(try fr2.find(FR2.self).actualView().proceedInWorkflow()) -// } -// } -// } -// -// wait(for: [expectOnFinish, expectViewLoaded], timeout: TestConstant.timeout) -// } -// -//} +// SwiftCurrent_ModalTests.swift +// SwiftCurrent +// +// Created by Tyler Thompson on 7/12/21. +// Copyright © 2021 WWT and Tyler Thompson. All rights reserved. +// + +import XCTest +import SwiftUI + +import SwiftCurrent + +@testable import ViewInspector +@testable import SwiftCurrent_SwiftUI // testable sadly needed for inspection.inspect to work + +@available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +extension InspectableView where View == ViewType.Sheet { + func isPresented() throws -> Bool { + return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false + } +} + +@available(iOS 15.0, macOS 11, tvOS 14.0, watchOS 7.0, *) +final class SwiftCurrent_ModalTests: XCTestCase, Scene { + func testWorkflowCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + let expectOnFinish = expectation(description: "OnFinish called") + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self).presentationType(.modal) + } + } + .onFinish { _ in + expectOnFinish.fulfill() + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + XCTAssertEqual(try wfr1.find(FR1.self).text().string(), "FR1 type") + try await wfr1.find(FR1.self).proceedInWorkflow() + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr1.find(ViewType.Sheet.self).isPresented()) + + let fr2 = try wfr1.find(ViewType.Sheet.self).find(FR2.self) + XCTAssertEqual(try fr2.text().string(), "FR2 type") + try await fr2.proceedInWorkflow() + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } + + func testWorkflowItemsOfTheSameTypeCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR1.self) { + thenProceed(with: FR1.self).presentationType(.modal) + }.presentationType(.modal) + } + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + try await wfr1.find(FR1.self).proceedInWorkflow() + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr1.find(ViewType.Sheet.self).isPresented()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + try await wfr2.find(FR1.self).proceedInWorkflow() + try await wfr2.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr2.find(ViewType.Sheet.self).isPresented()) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + try await wfr3.find(FR1.self).proceedInWorkflow() + try await wfr3.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + } + + func testLargeWorkflowCanBeFollowed() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR4 type") } + } + struct FR5: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR5 type") } + } + struct FR6: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR6 type") } + } + struct FR7: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR7 type") } + } + + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self) { + thenProceed(with: FR5.self) { + thenProceed(with: FR6.self) { + thenProceed(with: FR7.self).presentationType(.modal) + }.presentationType(.modal) + }.presentationType(.modal) + }.presentationType(.modal) + }.presentationType(.modal) + }.presentationType(.modal) + } + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + try await wfr1.find(FR1.self).proceedInWorkflow() + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr1.find(ViewType.Sheet.self).isPresented()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + try await wfr2.find(FR2.self).proceedInWorkflow() + try await wfr2.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr2.find(ViewType.Sheet.self).isPresented()) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + try await wfr3.find(FR3.self).proceedInWorkflow() + try await wfr3.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr3.find(ViewType.Sheet.self).isPresented()) + + let wfr4 = try await wfr3.extractWrappedWorkflowItem() + try await wfr4.find(FR4.self).proceedInWorkflow() + try await wfr4.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr4.find(ViewType.Sheet.self).isPresented()) + + let wfr5 = try await wfr4.extractWrappedWorkflowItem() + try await wfr5.find(FR5.self).proceedInWorkflow() + try await wfr5.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr5.find(ViewType.Sheet.self).isPresented()) + + let wfr6 = try await wfr5.extractWrappedWorkflowItem() + try await wfr6.find(FR6.self).proceedInWorkflow() + try await wfr6.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr6.find(ViewType.Sheet.self).isPresented()) + + let wfr7 = try await wfr6.extractWrappedWorkflowItem() + try await wfr7.find(FR7.self).proceedInWorkflow() + } + + func testNavLinkWorkflowsCanSkipTheFirstItem() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + func shouldLoad() -> Bool { false } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self).presentationType(.modal) + }.presentationType(.modal) + } + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + XCTAssertThrowsError(try wfr1.find(FR1.self)) + XCTAssertNoThrow(try wfr1.find(FR2.self)) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + try await wfr2.find(FR2.self).proceedInWorkflow() + try await wfr2.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr2.find(ViewType.Sheet.self).isPresented()) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + try await wfr3.find(FR3.self).proceedInWorkflow() + } + + func testNavLinkWorkflowsCanSkipOneItemInTheMiddle() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + func shouldLoad() -> Bool { false } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self).presentationType(.modal) + }.presentationType(.modal) + } + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + try await wfr1.find(FR1.self).proceedInWorkflow() + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr1.find(ViewType.Sheet.self).isPresented()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr2.find(FR2.self)) + XCTAssertNoThrow(try wfr2.find(FR3.self)) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + try await wfr3.find(FR3.self).proceedInWorkflow() + } + + func testNavLinkWorkflowsCanSkipTwoItemsInTheMiddle() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + func shouldLoad() -> Bool { false } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + func shouldLoad() -> Bool { false } + } + struct FR4: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + } + + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self) { + thenProceed(with: FR4.self).presentationType(.modal) + } + }.presentationType(.modal) + } + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + try await wfr1.find(FR1.self).proceedInWorkflow() + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr1.find(ViewType.Sheet.self).isPresented()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr2.find(FR2.self)) + XCTAssertNoThrow(try wfr2.find(FR4.self)) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr3.find(FR3.self)) + XCTAssertNoThrow(try wfr3.find(FR4.self)) + + let wfr4 = try await wfr3.extractWrappedWorkflowItem() + try await wfr4.find(FR4.self).proceedInWorkflow() + } + + func testNavLinkWorkflowsCanSkipLastItem() async throws { + struct FR1: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR1 type") } + } + struct FR2: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR2 type") } + } + struct FR3: View, FlowRepresentable, Inspectable { + var _workflowPointer: AnyFlowRepresentable? + var body: some View { Text("FR3 type") } + func shouldLoad() -> Bool { false } + } + + let expectOnFinish = expectation(description: "onFinish called") + let wfr1 = try await MainActor.run { + WorkflowLauncher(isLaunched: .constant(true)) { + thenProceed(with: FR1.self) { + thenProceed(with: FR2.self) { + thenProceed(with: FR3.self).presentationType(.modal) + }.presentationType(.modal) + } + } + .onFinish { _ in + expectOnFinish.fulfill() + } + } + .hostAndInspect(with: \.inspection) + .extractWorkflowItem() + + let model = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_model") as? EnvironmentObject)?.wrappedValue) + } + let launcher = try await MainActor.run { + try XCTUnwrap((Mirror(reflecting: try wfr1.actualView()).descendant("_launcher") as? EnvironmentObject)?.wrappedValue) + } + + try await wfr1.find(FR1.self).proceedInWorkflow() + try await wfr1.actualView().host { $0.environmentObject(model).environmentObject(launcher) } + XCTAssertTrue(try wfr1.find(ViewType.Sheet.self).isPresented()) + + let wfr2 = try await wfr1.extractWrappedWorkflowItem() + try await wfr2.find(FR2.self).proceedInWorkflow() + XCTAssertThrowsError(try wfr2.find(FR3.self)) + + let wfr3 = try await wfr2.extractWrappedWorkflowItem() + XCTAssertThrowsError(try wfr3.find(FR3.self)) + + wait(for: [expectOnFinish], timeout: TestConstant.timeout) + } +} From 944442e12d5b203e2c7f9fb8e8a36ee8fd474cac Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Tue, 8 Feb 2022 12:39:29 -0700 Subject: [PATCH 35/37] [skip ci] async-swiftui-tests - Superfluous return removal - TT --- Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift index f3c65704d..67d2e0c42 100644 --- a/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/SwiftCurrent_ModalTests.swift @@ -17,7 +17,7 @@ import SwiftCurrent @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) extension InspectableView where View == ViewType.Sheet { func isPresented() throws -> Bool { - return (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false + (Mirror(reflecting: content.view).descendant("presenter", "isPresented") as? Binding)?.wrappedValue ?? false } } From c39a0093d4e3f209c554900c7175fa30f1ffb2be Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Wed, 23 Feb 2022 10:14:44 -0700 Subject: [PATCH 36/37] [async-swiftui-tests] - The pipelien will maybe possibly pass? - TT MF Co-authored-by: Matt Freiburg --- .../GenericConstraintTests.swift | 3 +-- .../ViewInspector/ViewHostingExtensions.swift | 14 ++++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index 7b5e7ee7e..e6e37eda6 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -1431,8 +1431,7 @@ final class GenericConstraintTests: XCTestCase, View { }.hostAndInspect(with: \.inspection).extractWorkflowItem() try await workflowView.find(FR0.self).proceedInWorkflow() - let view = try await workflowView.extractWrappedWorkflowItem() - XCTAssertEqual(try view.find(FR1.self).actualView().persistence, .removedAfterProceeding) + XCTAssertEqual(try workflowView.find(FR1.self).actualView().persistence, .removedAfterProceeding) } func testProceedingWhenInputIsAnyWorkflowPassedArgs_FlowPersistenceCanBeSetWithClosure() async throws { diff --git a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift index a33364805..15f91d8af 100644 --- a/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift +++ b/Tests/SwiftCurrent_SwiftUITests/ViewInspector/ViewHostingExtensions.swift @@ -96,16 +96,14 @@ public extension InspectionEmissary where V: View & Inspectable { function: String = #function, file: StaticString = #file, line: UInt = #line) async throws -> InspectableView> { - try await withCheckedThrowingContinuation { continuation in - do { - var v: InspectableView>? + await withCheckedContinuation { continuation in + DispatchQueue.main.async { let exp = self.inspect(after: delay, function: function, file: file, line: line) { view in - v = view + continuation.resume(returning: view) + } + DispatchQueue.global(qos: .background).async { + XCTWaiter().wait(for: [exp], timeout: TestConstant.timeout) } - XCTWaiter().wait(for: [exp], timeout: TestConstant.timeout) - continuation.resume(returning: try XCTUnwrap(v, "view type \(String(describing: V.self)) not inspected")) - } catch { - continuation.resume(throwing: error) } } } From 99b405f823b60c44202bed60a742e3a084248340 Mon Sep 17 00:00:00 2001 From: Tyler Thompson Date: Wed, 23 Feb 2022 10:25:41 -0700 Subject: [PATCH 37/37] [async-swiftui-tests] - Fixed the whitespace thing Nick didn't like - TT --- Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift index e6e37eda6..989cb32a4 100644 --- a/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift +++ b/Tests/SwiftCurrent_SwiftUITests/GenericConstraintTests.swift @@ -1125,7 +1125,6 @@ final class GenericConstraintTests: XCTestCase, View { try await workflowView.find(FR0.self).proceedInWorkflow() let workflowItem = try await workflowView.extractWrappedWorkflowItem() - try await workflowItem.find(FR1.self).proceedInWorkflow() let view = try await workflowItem.extractWrappedWorkflowItem()