From 717b8588ea4400c89c463cc768110d60bf296b22 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Wed, 1 Jun 2022 13:58:31 +0200 Subject: [PATCH] Setup app, landing, and session features --- .../xcschemes/LandingFeature.xcscheme | 78 +++++++++++ .../xcschemes/SessionFeature.xcscheme | 78 +++++++++++ .../xcschemes/example-app.xcscheme | 126 ++++++++++++++++++ Example/ExampleApp/Package.swift | 42 +++++- .../ExampleApp/Sources/AppFeature/App.swift | 18 ++- .../Sources/AppFeature/AppFeature.swift | 82 ++++++++++++ .../Sources/AppFeature/AppView.swift | 66 ++++++++- .../LandingFeature/LandingFeature.swift | 27 ++++ .../Sources/LandingFeature/LandingView.swift | 38 ++++++ .../SessionFeature/SessionFeature.swift | 27 ++++ .../Sources/SessionFeature/SessionView.swift | 35 +++++ .../AppFeatureTests/AppFeatureTests.swift | 11 +- .../LandingFeatureTests.swift | 15 +++ .../SessionFeatureTests.swift | 15 +++ 14 files changed, 651 insertions(+), 7 deletions(-) create mode 100644 Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/LandingFeature.xcscheme create mode 100644 Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/SessionFeature.xcscheme create mode 100644 Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/example-app.xcscheme create mode 100644 Example/ExampleApp/Sources/AppFeature/AppFeature.swift create mode 100644 Example/ExampleApp/Sources/LandingFeature/LandingFeature.swift create mode 100644 Example/ExampleApp/Sources/LandingFeature/LandingView.swift create mode 100644 Example/ExampleApp/Sources/SessionFeature/SessionFeature.swift create mode 100644 Example/ExampleApp/Sources/SessionFeature/SessionView.swift create mode 100644 Example/ExampleApp/Tests/LandingFeatureTests/LandingFeatureTests.swift create mode 100644 Example/ExampleApp/Tests/SessionFeatureTests/SessionFeatureTests.swift diff --git a/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/LandingFeature.xcscheme b/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/LandingFeature.xcscheme new file mode 100644 index 00000000..7d203fde --- /dev/null +++ b/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/LandingFeature.xcscheme @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "1340" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "LandingFeature" + BuildableName = "LandingFeature" + BlueprintName = "LandingFeature" + ReferencedContainer = "container:"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "LandingFeatureTests" + BuildableName = "LandingFeatureTests" + BlueprintName = "LandingFeatureTests" + ReferencedContainer = "container:"> + </BuildableReference> + </TestableReference> + </Testables> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "LandingFeature" + BuildableName = "LandingFeature" + BlueprintName = "LandingFeature" + ReferencedContainer = "container:"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/SessionFeature.xcscheme b/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/SessionFeature.xcscheme new file mode 100644 index 00000000..9361c555 --- /dev/null +++ b/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/SessionFeature.xcscheme @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "1340" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "SessionFeature" + BuildableName = "SessionFeature" + BlueprintName = "SessionFeature" + ReferencedContainer = "container:"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "SessionFeatureTests" + BuildableName = "SessionFeatureTests" + BlueprintName = "SessionFeatureTests" + ReferencedContainer = "container:"> + </BuildableReference> + </TestableReference> + </Testables> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "SessionFeature" + BuildableName = "SessionFeature" + BlueprintName = "SessionFeature" + ReferencedContainer = "container:"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/example-app.xcscheme b/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/example-app.xcscheme new file mode 100644 index 00000000..6901d433 --- /dev/null +++ b/Example/ExampleApp/.swiftpm/xcode/xcshareddata/xcschemes/example-app.xcscheme @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "1340" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "AppFeature" + BuildableName = "AppFeature" + BlueprintName = "AppFeature" + ReferencedContainer = "container:"> + </BuildableReference> + </BuildActionEntry> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "LandingFeature" + BuildableName = "LandingFeature" + BlueprintName = "LandingFeature" + ReferencedContainer = "container:"> + </BuildableReference> + </BuildActionEntry> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "SessionFeature" + BuildableName = "SessionFeature" + BlueprintName = "SessionFeature" + ReferencedContainer = "container:"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "AppFeatureTests" + BuildableName = "AppFeatureTests" + BlueprintName = "AppFeatureTests" + ReferencedContainer = "container:"> + </BuildableReference> + </TestableReference> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "LandingFeatureTests" + BuildableName = "LandingFeatureTests" + BlueprintName = "LandingFeatureTests" + ReferencedContainer = "container:"> + </BuildableReference> + </TestableReference> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "SessionFeatureTests" + BuildableName = "SessionFeatureTests" + BlueprintName = "SessionFeatureTests" + ReferencedContainer = "container:"> + </BuildableReference> + </TestableReference> + </Testables> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "AppFeature" + BuildableName = "AppFeature" + BlueprintName = "AppFeature" + ReferencedContainer = "container:"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/Example/ExampleApp/Package.swift b/Example/ExampleApp/Package.swift index 3e3cec1e..409928d4 100644 --- a/Example/ExampleApp/Package.swift +++ b/Example/ExampleApp/Package.swift @@ -3,7 +3,7 @@ import PackageDescription let package = Package( - name: "ExampleApp", + name: "example-app", platforms: [ .iOS(.v15), ], @@ -12,6 +12,14 @@ let package = Package( name: "AppFeature", targets: ["AppFeature"] ), + .library( + name: "LandingFeature", + targets: ["LandingFeature"] + ), + .library( + name: "SessionFeature", + targets: ["SessionFeature"] + ), ], dependencies: [ .package(path: "../../"), // elixxir-dapps-sdk-swift @@ -28,6 +36,8 @@ let package = Package( .target( name: "AppFeature", dependencies: [ + .target(name: "LandingFeature"), + .target(name: "SessionFeature"), .product( name: "ElixxirDAppsSDK", package: "elixxir-dapps-sdk-swift" @@ -48,5 +58,35 @@ let package = Package( .target(name: "AppFeature"), ] ), + .target( + name: "LandingFeature", + dependencies: [ + .product( + name: "ComposableArchitecture", + package: "swift-composable-architecture" + ), + ] + ), + .testTarget( + name: "LandingFeatureTests", + dependencies: [ + .target(name: "LandingFeature"), + ] + ), + .target( + name: "SessionFeature", + dependencies: [ + .product( + name: "ComposableArchitecture", + package: "swift-composable-architecture" + ), + ] + ), + .testTarget( + name: "SessionFeatureTests", + dependencies: [ + .target(name: "SessionFeature"), + ] + ), ] ) diff --git a/Example/ExampleApp/Sources/AppFeature/App.swift b/Example/ExampleApp/Sources/AppFeature/App.swift index 47af3dbc..0374fa69 100644 --- a/Example/ExampleApp/Sources/AppFeature/App.swift +++ b/Example/ExampleApp/Sources/AppFeature/App.swift @@ -1,10 +1,26 @@ +import ComposableArchitecture +import LandingFeature +import SessionFeature import SwiftUI @main struct App: SwiftUI.App { var body: some Scene { WindowGroup { - AppView() + AppView(store: Store( + initialState: AppState(), + reducer: appReducer, + environment: .live() + )) } } } + +extension AppEnvironment { + static func live() -> AppEnvironment { + AppEnvironment( + landing: LandingEnvironment(), + session: SessionEnvironment() + ) + } +} diff --git a/Example/ExampleApp/Sources/AppFeature/AppFeature.swift b/Example/ExampleApp/Sources/AppFeature/AppFeature.swift new file mode 100644 index 00000000..07d6812a --- /dev/null +++ b/Example/ExampleApp/Sources/AppFeature/AppFeature.swift @@ -0,0 +1,82 @@ +import ComposableArchitecture +import ComposablePresentation +import LandingFeature +import SessionFeature + +struct AppState: Equatable { + enum Scene: Equatable { + case landing(LandingState) + case session(SessionState) + } + + var scene: Scene = .landing(LandingState()) +} + +extension AppState.Scene { + var asLanding: LandingState? { + get { + guard case .landing(let state) = self else { return nil } + return state + } + set { + guard let newValue = newValue else { return } + self = .landing(newValue) + } + } + + var asSession: SessionState? { + get { + guard case .session(let state) = self else { return nil } + return state + } + set { + guard let newValue = newValue else { return } + self = .session(newValue) + } + } +} + +enum AppAction: Equatable { + case viewDidLoad + case landing(LandingAction) + case session(SessionAction) +} + +struct AppEnvironment { + var landing: LandingEnvironment + var session: SessionEnvironment +} + +let appReducer = Reducer<AppState, AppAction, AppEnvironment> +{ state, action, env in + switch action { + case .viewDidLoad: + return .none + + case .landing(_), .session(_): + return .none + } +} +.presenting( + landingReducer, + state: .keyPath(\.scene.asLanding), + id: .notNil(), + action: /AppAction.landing, + environment: \.landing +) +.presenting( + sessionReducer, + state: .keyPath(\.scene.asSession), + id: .notNil(), + action: /AppAction.session, + environment: \.session +) + +#if DEBUG +extension AppEnvironment { + static let failing = AppEnvironment( + landing: .failing, + session: .failing + ) +} +#endif diff --git a/Example/ExampleApp/Sources/AppFeature/AppView.swift b/Example/ExampleApp/Sources/AppFeature/AppView.swift index ac856328..f2af2d1a 100644 --- a/Example/ExampleApp/Sources/AppFeature/AppView.swift +++ b/Example/ExampleApp/Sources/AppFeature/AppView.swift @@ -1,16 +1,76 @@ +import ComposableArchitecture +import LandingFeature +import SessionFeature import SwiftUI struct AppView: View { + let store: Store<AppState, AppAction> + + struct ViewState: Equatable { + enum Scene: Equatable { + case landing + case session + } + + let scene: Scene + + init(state: AppState) { + switch state.scene { + case .landing(_): + self.scene = .landing + + case .session(_): + self.scene = .session + } + } + } + var body: some View { - Text("AppView") - .padding() + WithViewStore(store.scope(state: ViewState.init)) { viewStore in + ZStack { + SwitchStore(store.scope(state: \.scene)) { + CaseLet( + state: /AppState.Scene.landing, + action: AppAction.landing, + then: { store in + NavigationView { + LandingView(store: store) + } + .navigationViewStyle(.stack) + .transition(.move(edge: .leading)) + } + ) + + CaseLet( + state: /AppState.Scene.session, + action: AppAction.session, + then: { store in + NavigationView { + SessionView(store: store) + } + .navigationViewStyle(.stack) + .transition(.move(edge: .trailing)) + } + ) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + .animation(.default, value: viewStore.scene) + .task { + viewStore.send(.viewDidLoad) + } + } } } #if DEBUG struct AppView_Previews: PreviewProvider { static var previews: some View { - AppView() + AppView(store: Store( + initialState: AppState(), + reducer: .empty, + environment: () + )) } } #endif diff --git a/Example/ExampleApp/Sources/LandingFeature/LandingFeature.swift b/Example/ExampleApp/Sources/LandingFeature/LandingFeature.swift new file mode 100644 index 00000000..b145b250 --- /dev/null +++ b/Example/ExampleApp/Sources/LandingFeature/LandingFeature.swift @@ -0,0 +1,27 @@ +import ComposableArchitecture + +public struct LandingState: Equatable { + public init() {} +} + +public enum LandingAction: Equatable { + case viewDidLoad +} + +public struct LandingEnvironment { + public init() {} +} + +public let landingReducer = Reducer<LandingState, LandingAction, LandingEnvironment> +{ state, action, env in + switch action { + case .viewDidLoad: + return .none + } +} + +#if DEBUG +extension LandingEnvironment { + public static let failing = LandingEnvironment() +} +#endif diff --git a/Example/ExampleApp/Sources/LandingFeature/LandingView.swift b/Example/ExampleApp/Sources/LandingFeature/LandingView.swift new file mode 100644 index 00000000..5ebc5e89 --- /dev/null +++ b/Example/ExampleApp/Sources/LandingFeature/LandingView.swift @@ -0,0 +1,38 @@ +import ComposableArchitecture +import SwiftUI + +public struct LandingView: View { + public init(store: Store<LandingState, LandingAction>) { + self.store = store + } + + let store: Store<LandingState, LandingAction> + + struct ViewState: Equatable { + init(state: LandingState) {} + } + + public var body: some View { + WithViewStore(store.scope(state: ViewState.init)) { viewStore in + Text("LandingView") + .task { + viewStore.send(.viewDidLoad) + } + } + } +} + +#if DEBUG +public struct LandingView_Previews: PreviewProvider { + public static var previews: some View { + NavigationView { + LandingView(store: .init( + initialState: .init(), + reducer: .empty, + environment: () + )) + } + .navigationViewStyle(.stack) + } +} +#endif diff --git a/Example/ExampleApp/Sources/SessionFeature/SessionFeature.swift b/Example/ExampleApp/Sources/SessionFeature/SessionFeature.swift new file mode 100644 index 00000000..3b7dd16f --- /dev/null +++ b/Example/ExampleApp/Sources/SessionFeature/SessionFeature.swift @@ -0,0 +1,27 @@ +import ComposableArchitecture + +public struct SessionState: Equatable { + public init() {} +} + +public enum SessionAction: Equatable { + case viewDidLoad +} + +public struct SessionEnvironment { + public init() {} +} + +public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironment> +{ state, action, env in + switch action { + case .viewDidLoad: + return .none + } +} + +#if DEBUG +extension SessionEnvironment { + public static let failing = SessionEnvironment() +} +#endif diff --git a/Example/ExampleApp/Sources/SessionFeature/SessionView.swift b/Example/ExampleApp/Sources/SessionFeature/SessionView.swift new file mode 100644 index 00000000..781ee440 --- /dev/null +++ b/Example/ExampleApp/Sources/SessionFeature/SessionView.swift @@ -0,0 +1,35 @@ +import ComposableArchitecture +import SwiftUI + +public struct SessionView: View { + public init(store: Store<SessionState, SessionAction>) { + self.store = store + } + + let store: Store<SessionState, SessionAction> + + struct ViewState: Equatable { + init(state: SessionState) {} + } + + public var body: some View { + WithViewStore(store.scope(state: ViewState.init)) { viewStore in + Text("SessionView") + .task { + viewStore.send(.viewDidLoad) + } + } + } +} + +#if DEBUG +public struct SessionView_Previews: PreviewProvider { + public static var previews: some View { + SessionView(store: .init( + initialState: .init(), + reducer: .empty, + environment: () + )) + } +} +#endif diff --git a/Example/ExampleApp/Tests/AppFeatureTests/AppFeatureTests.swift b/Example/ExampleApp/Tests/AppFeatureTests/AppFeatureTests.swift index 23825304..2fe7038c 100644 --- a/Example/ExampleApp/Tests/AppFeatureTests/AppFeatureTests.swift +++ b/Example/ExampleApp/Tests/AppFeatureTests/AppFeatureTests.swift @@ -1,8 +1,15 @@ +import ComposableArchitecture import XCTest @testable import AppFeature final class AppFeatureTests: XCTestCase { - func testExample() throws { - XCTAssert(true) + func testViewDidLoad() throws { + let store = TestStore( + initialState: AppState(), + reducer: appReducer, + environment: .failing + ) + + store.send(.viewDidLoad) } } diff --git a/Example/ExampleApp/Tests/LandingFeatureTests/LandingFeatureTests.swift b/Example/ExampleApp/Tests/LandingFeatureTests/LandingFeatureTests.swift new file mode 100644 index 00000000..389863f6 --- /dev/null +++ b/Example/ExampleApp/Tests/LandingFeatureTests/LandingFeatureTests.swift @@ -0,0 +1,15 @@ +import ComposableArchitecture +import XCTest +@testable import LandingFeature + +final class LandingFeatureTests: XCTestCase { + func testViewDidLoad() throws { + let store = TestStore( + initialState: LandingState(), + reducer: landingReducer, + environment: .failing + ) + + store.send(.viewDidLoad) + } +} diff --git a/Example/ExampleApp/Tests/SessionFeatureTests/SessionFeatureTests.swift b/Example/ExampleApp/Tests/SessionFeatureTests/SessionFeatureTests.swift new file mode 100644 index 00000000..5ed11e32 --- /dev/null +++ b/Example/ExampleApp/Tests/SessionFeatureTests/SessionFeatureTests.swift @@ -0,0 +1,15 @@ +import ComposableArchitecture +import XCTest +@testable import SessionFeature + +final class SessionFeatureTests: XCTestCase { + func testViewDidLoad() throws { + let store = TestStore( + initialState: SessionState(), + reducer: sessionReducer, + environment: .failing + ) + + store.send(.viewDidLoad) + } +} -- GitLab