diff --git a/docs/ExampleApp/LICENSE b/docs/ExampleApp/LICENSE new file mode 100644 index 0000000..8ddf8cf --- /dev/null +++ b/docs/ExampleApp/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Daniel Bernal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/ExampleApp/README.md b/docs/ExampleApp/README.md index 09ddf81..acd1073 100644 --- a/docs/ExampleApp/README.md +++ b/docs/ExampleApp/README.md @@ -1,3 +1,4 @@ # WireKit Sample App -This is a quick demo app that fetches a random list of ToDos from a mock service and mocks additions. +### This project is Archived. +The latest Wirekit Sample application is available of the [library documentation](https://github.com/afterxleep/WireKit/tree/main/docs/ExampleApp). diff --git a/docs/ExampleApp/WireKitSample.xcodeproj/project.pbxproj b/docs/ExampleApp/WireKitSample.xcodeproj/project.pbxproj index 0eb0c14..f074c23 100644 --- a/docs/ExampleApp/WireKitSample.xcodeproj/project.pbxproj +++ b/docs/ExampleApp/WireKitSample.xcodeproj/project.pbxproj @@ -17,8 +17,23 @@ D6B466AA25980D2B00695194 /* WireKit in Frameworks */ = {isa = PBXBuildFile; productRef = D6B466A925980D2B00695194 /* WireKit */; }; D6B466AF25980F4000695194 /* TodoAddView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B466AE25980F4000695194 /* TodoAddView.swift */; }; D6C59FA6258C5D8700AAEDCF /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C59FA5258C5D8700AAEDCF /* Empty.swift */; }; + D6E759A329FD0A0D00E058E3 /* WireKitSampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E759A229FD0A0D00E058E3 /* WireKitSampleTests.swift */; }; + D6E759A929FD0A1300E058E3 /* TodoListViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E7599A29FD09D800E058E3 /* TodoListViewModelTests.swift */; }; + D6E759AD29FD14F800E058E3 /* todoItems.json in Resources */ = {isa = PBXBuildFile; fileRef = D6E759AC29FD14BB00E058E3 /* todoItems.json */; }; + D6E759B329FD158E00E058E3 /* URLProtocolMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E759AA29FD0B4000E058E3 /* URLProtocolMock.swift */; }; + D6E759B429FD168800E058E3 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E759B129FD156000E058E3 /* TestHelpers.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + D6E759A429FD0A0D00E058E3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D68B254C257DD2550019B48A /* Project object */; + proxyType = 1; + remoteGlobalIDString = D68B2553257DD2550019B48A; + remoteInfo = WireKitSample; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ D68B2554257DD2550019B48A /* WireKitSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireKitSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; D68B2557257DD2550019B48A /* WireKitSampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireKitSampleApp.swift; sourceTree = ""; }; @@ -31,6 +46,12 @@ D68B2579257DD7070019B48A /* TodoAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoAPI.swift; sourceTree = ""; }; D6B466AE25980F4000695194 /* TodoAddView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoAddView.swift; sourceTree = ""; }; D6C59FA5258C5D8700AAEDCF /* Empty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Empty.swift; sourceTree = ""; }; + D6E7599A29FD09D800E058E3 /* TodoListViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoListViewModelTests.swift; sourceTree = ""; }; + D6E759A029FD0A0D00E058E3 /* WireKitSampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WireKitSampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D6E759A229FD0A0D00E058E3 /* WireKitSampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireKitSampleTests.swift; sourceTree = ""; }; + D6E759AA29FD0B4000E058E3 /* URLProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLProtocolMock.swift; sourceTree = ""; }; + D6E759AC29FD14BB00E058E3 /* todoItems.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = todoItems.json; sourceTree = ""; }; + D6E759B129FD156000E058E3 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -42,6 +63,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D6E7599D29FD0A0D00E058E3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -49,6 +77,7 @@ isa = PBXGroup; children = ( D68B2556257DD2550019B48A /* WireKitSample */, + D6E759A129FD0A0D00E058E3 /* WireKitSampleTests */, D68B2555257DD2550019B48A /* Products */, ); sourceTree = ""; @@ -57,6 +86,7 @@ isa = PBXGroup; children = ( D68B2554257DD2550019B48A /* WireKitSample.app */, + D6E759A029FD0A0D00E058E3 /* WireKitSampleTests.xctest */, ); name = Products; sourceTree = ""; @@ -72,6 +102,7 @@ D68B255B257DD2560019B48A /* Assets.xcassets */, D68B2560257DD2560019B48A /* Info.plist */, D68B255D257DD2560019B48A /* Preview Content */, + D6E7599929FD09C000E058E3 /* Tests */, ); path = WireKitSample; sourceTree = ""; @@ -94,6 +125,41 @@ path = TodoList; sourceTree = ""; }; + D6E7599929FD09C000E058E3 /* Tests */ = { + isa = PBXGroup; + children = ( + D6E759B129FD156000E058E3 /* TestHelpers.swift */, + D6E759AA29FD0B4000E058E3 /* URLProtocolMock.swift */, + D6E759AF29FD151000E058E3 /* TodoList */, + D6E759AE29FD14FC00E058E3 /* Sample Data */, + ); + path = Tests; + sourceTree = ""; + }; + D6E759A129FD0A0D00E058E3 /* WireKitSampleTests */ = { + isa = PBXGroup; + children = ( + D6E759A229FD0A0D00E058E3 /* WireKitSampleTests.swift */, + ); + path = WireKitSampleTests; + sourceTree = ""; + }; + D6E759AE29FD14FC00E058E3 /* Sample Data */ = { + isa = PBXGroup; + children = ( + D6E759AC29FD14BB00E058E3 /* todoItems.json */, + ); + path = "Sample Data"; + sourceTree = ""; + }; + D6E759AF29FD151000E058E3 /* TodoList */ = { + isa = PBXGroup; + children = ( + D6E7599A29FD09D800E058E3 /* TodoListViewModelTests.swift */, + ); + path = TodoList; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -117,18 +183,40 @@ productReference = D68B2554257DD2550019B48A /* WireKitSample.app */; productType = "com.apple.product-type.application"; }; + D6E7599F29FD0A0D00E058E3 /* WireKitSampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D6E759A629FD0A0D00E058E3 /* Build configuration list for PBXNativeTarget "WireKitSampleTests" */; + buildPhases = ( + D6E7599C29FD0A0D00E058E3 /* Sources */, + D6E7599D29FD0A0D00E058E3 /* Frameworks */, + D6E7599E29FD0A0D00E058E3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D6E759A529FD0A0D00E058E3 /* PBXTargetDependency */, + ); + name = WireKitSampleTests; + productName = WireKitSampleTests; + productReference = D6E759A029FD0A0D00E058E3 /* WireKitSampleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D68B254C257DD2550019B48A /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1220; + LastSwiftUpdateCheck = 1430; LastUpgradeCheck = 1220; TargetAttributes = { D68B2553257DD2550019B48A = { CreatedOnToolsVersion = 12.2; }; + D6E7599F29FD0A0D00E058E3 = { + CreatedOnToolsVersion = 14.3; + TestTargetID = D68B2553257DD2550019B48A; + }; }; }; buildConfigurationList = D68B254F257DD2550019B48A /* Build configuration list for PBXProject "WireKitSample" */; @@ -148,6 +236,7 @@ projectRoot = ""; targets = ( D68B2553257DD2550019B48A /* WireKitSample */, + D6E7599F29FD0A0D00E058E3 /* WireKitSampleTests */, ); }; /* End PBXProject section */ @@ -162,6 +251,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D6E7599E29FD0A0D00E058E3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D6E759AD29FD14F800E058E3 /* todoItems.json in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -170,6 +267,7 @@ buildActionMask = 2147483647; files = ( D6B466AF25980F4000695194 /* TodoAddView.swift in Sources */, + D6E759B329FD158E00E058E3 /* URLProtocolMock.swift in Sources */, D68B255A257DD2550019B48A /* TodoListView.swift in Sources */, D68B257A257DD7070019B48A /* TodoAPI.swift in Sources */, D68B2558257DD2550019B48A /* WireKitSampleApp.swift in Sources */, @@ -179,8 +277,26 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D6E7599C29FD0A0D00E058E3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D6E759A929FD0A1300E058E3 /* TodoListViewModelTests.swift in Sources */, + D6E759A329FD0A0D00E058E3 /* WireKitSampleTests.swift in Sources */, + D6E759B429FD168800E058E3 /* TestHelpers.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + D6E759A529FD0A0D00E058E3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D68B2553257DD2550019B48A /* WireKitSample */; + targetProxy = D6E759A429FD0A0D00E058E3 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ D68B2561257DD2560019B48A /* Debug */ = { isa = XCBuildConfiguration; @@ -342,6 +458,46 @@ }; name = Release; }; + D6E759A729FD0A0D00E058E3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = JM9222EF99; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.banshai.WireKitSampleTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WireKitSample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/WireKitSample"; + }; + name = Debug; + }; + D6E759A829FD0A0D00E058E3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = JM9222EF99; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.banshai.WireKitSampleTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WireKitSample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/WireKitSample"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -363,6 +519,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D6E759A629FD0A0D00E058E3 /* Build configuration list for PBXNativeTarget "WireKitSampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D6E759A729FD0A0D00E058E3 /* Debug */, + D6E759A829FD0A0D00E058E3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ @@ -370,7 +535,7 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "git@github.com:afterxleep/WireKit.git"; requirement = { - kind = upToNextMajorVersion; + kind = upToNextMinorVersion; minimumVersion = 1.0.0; }; }; diff --git a/docs/ExampleApp/WireKitSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/docs/ExampleApp/WireKitSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 5bf2286..c199d84 100644 --- a/docs/ExampleApp/WireKitSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/docs/ExampleApp/WireKitSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,14 +1,16 @@ { - "pins" : [ - { - "identity" : "wirekit", - "kind" : "remoteSourceControl", - "location" : "git@github.com:afterxleep/WireKit.git", - "state" : { - "revision" : "97c8ee70482ebf1883ca642621a066217f399c27", - "version" : "1.0.3" + "object": { + "pins": [ + { + "package": "WireKit", + "repositoryURL": "git@github.com:afterxleep/WireKit.git", + "state": { + "branch": null, + "revision": "f9eecd8b1e84fa2d1616b00743d47200a84d69bf", + "version": "1.0.0" + } } - } - ], - "version" : 2 + ] + }, + "version": 1 } diff --git a/docs/ExampleApp/WireKitSample.xcodeproj/xcshareddata/xcschemes/WireKitSample.xcscheme b/docs/ExampleApp/WireKitSample.xcodeproj/xcshareddata/xcschemes/WireKitSample.xcscheme index eeed644..ce701c4 100644 --- a/docs/ExampleApp/WireKitSample.xcodeproj/xcshareddata/xcschemes/WireKitSample.xcscheme +++ b/docs/ExampleApp/WireKitSample.xcodeproj/xcshareddata/xcschemes/WireKitSample.xcscheme @@ -28,6 +28,17 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + Data { + let testBundle = Bundle(for: type(of: self)) + guard let url = testBundle.url(forResource: fileName, withExtension: "json") else { + throw NSError(domain: "File not found", code: 1, userInfo: nil) + } + + return try Data(contentsOf: url) + } +} diff --git a/docs/ExampleApp/WireKitSample/Tests/TodoList/TodoListViewModelTests.swift b/docs/ExampleApp/WireKitSample/Tests/TodoList/TodoListViewModelTests.swift new file mode 100644 index 0000000..ec9fce3 --- /dev/null +++ b/docs/ExampleApp/WireKitSample/Tests/TodoList/TodoListViewModelTests.swift @@ -0,0 +1,63 @@ +// +// TodoListViewModelTests.swift +// WireKitSample +// +// Created by Daniel on 29/04/23. +// + +import Foundation +import XCTest +import Combine +import WireKit +@testable import WireKitSample + +class TodoListViewModelTests: XCTestCase { + + private var todoItemsCancellable: AnyCancellable? + + func testListModelWorks() { + + // Note that we're using non SSL urls here as URLProtocol does + // to avoid SSL errors in URLSession + let url = URL(string: "http://jsonplaceholder.typicode.com/todos") + + // Get some test data from a file + do { + let jsonData = try loadJSONDataFromFile(named: "todoItems") + URLProtocolMock.testURLs = [url: jsonData] + } catch { + XCTFail("Error loading JSON data: \(error)") + } + + // Use the Mock + let config = URLSessionConfiguration.ephemeral + config.protocolClasses = [URLProtocolMock.self] + + // Create a custom URL Session + let session = URLSession(configuration: config) + + // Initialize the APIClient and pass along a custom dispatcher + // Note that we're using non SSL urls here as + let baseURL = "http://jsonplaceholder.typicode.com" + + // Then + let dispatcher = WKNetworkDispatcher(urlSession: session) + let apiClient = WKAPIClient(baseURL: baseURL, networkDispatcher: dispatcher) + + let expectation = XCTestExpectation(description: "Wait for the response") + let model = TodoListViewModel(apiClient: apiClient) + todoItemsCancellable = model.$todoItems + .dropFirst() // To skip the initial (empty) value + .sink { todoItems in + XCTAssertGreaterThan(todoItems.count, 0, "Todo items should be loaded") + expectation.fulfill() + } + wait(for: [expectation], timeout: 10) + } + + deinit { + todoItemsCancellable?.cancel() + } + +} + diff --git a/docs/ExampleApp/WireKitSample/Tests/URLProtocolMock.swift b/docs/ExampleApp/WireKitSample/Tests/URLProtocolMock.swift new file mode 100644 index 0000000..ea1e27b --- /dev/null +++ b/docs/ExampleApp/WireKitSample/Tests/URLProtocolMock.swift @@ -0,0 +1,37 @@ +// +// URLProtocolMock.swift +// WireKitSampleTests +// +// Created by Daniel on 29/04/23. +// + +import Foundation + +class URLProtocolMock: URLProtocol { + + // Map URL's to test data + static var testURLs = [URL?: Data]() + + // Handle all requests + override class func canInit(with request: URLRequest) -> Bool { + return true + } + + override class func canonicalRequest(for request: URLRequest) -> URLRequest { + return request + } + + override func startLoading() { + if let url = request.url { + if let data = URLProtocolMock.testURLs[url] { + let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: nil) + self.client?.urlProtocol(self, didReceive: httpResponse!, cacheStoragePolicy: .notAllowed) + self.client?.urlProtocol(self, didLoad: data) + } + } + + self.client?.urlProtocolDidFinishLoading(self) + } + + override func stopLoading() { } +} diff --git a/docs/ExampleApp/WireKitSample/TodoList/TodoAddView.swift b/docs/ExampleApp/WireKitSample/TodoList/TodoAddView.swift index 7d15786..7af5c7f 100644 --- a/docs/ExampleApp/WireKitSample/TodoList/TodoAddView.swift +++ b/docs/ExampleApp/WireKitSample/TodoList/TodoAddView.swift @@ -8,9 +8,9 @@ import SwiftUI struct TodoAddView: View { - + @Environment(\.presentationMode) var presentationMode - @StateObject var viewModel = TodoListViewModel() + @StateObject var viewModel: TodoListViewModel @State var todoText: String = "" var body: some View { diff --git a/docs/ExampleApp/WireKitSample/TodoList/TodoListView.swift b/docs/ExampleApp/WireKitSample/TodoList/TodoListView.swift index 1ba5981..100304c 100644 --- a/docs/ExampleApp/WireKitSample/TodoList/TodoListView.swift +++ b/docs/ExampleApp/WireKitSample/TodoList/TodoListView.swift @@ -9,7 +9,7 @@ import SwiftUI struct TodoListView: View { - @StateObject var viewModel = TodoListViewModel() + @StateObject var viewModel: TodoListViewModel @State var showingAddForm: Bool = false var body: some View { @@ -46,7 +46,7 @@ extension TodoListView { action: { showingAddForm = true }) { Image(systemName: "plus.circle").imageScale(.medium) }.sheet(isPresented: $showingAddForm) { - TodoAddView() + TodoAddView(viewModel: viewModel) } } } @@ -61,12 +61,3 @@ extension TodoListView { } } } - -struct TodoListView_Previews: PreviewProvider { - static var previews: some View { - let viewModel = TodoListViewModel() - TodoListView(viewModel: viewModel, - showingAddForm: false) - } -} - diff --git a/docs/ExampleApp/WireKitSample/TodoList/TodoListViewModel.swift b/docs/ExampleApp/WireKitSample/TodoList/TodoListViewModel.swift index 07b44ff..f8c447b 100644 --- a/docs/ExampleApp/WireKitSample/TodoList/TodoListViewModel.swift +++ b/docs/ExampleApp/WireKitSample/TodoList/TodoListViewModel.swift @@ -17,7 +17,7 @@ class TodoListViewModel: ObservableObject { @Published var title = "Todo List" @Published var loadingMessage = "Loading Data..." - private var apiClient: WKAPIClient + let apiClient: WKAPIClient private var cancellables = [AnyCancellable]() private enum Constants { @@ -26,8 +26,8 @@ class TodoListViewModel: ObservableObject { static let defaultImage = "circle" } - init() { - apiClient = WKAPIClient(baseURL: Constants.apiURL) + init(apiClient: WKAPIClient) { + self.apiClient = apiClient loadData() } diff --git a/docs/ExampleApp/WireKitSample/WireKitSampleApp.swift b/docs/ExampleApp/WireKitSample/WireKitSampleApp.swift index 0ef6c25..c8d1567 100644 --- a/docs/ExampleApp/WireKitSample/WireKitSampleApp.swift +++ b/docs/ExampleApp/WireKitSample/WireKitSampleApp.swift @@ -6,12 +6,25 @@ // import SwiftUI +import WireKit @main struct WireKitSampleApp: App { + + let model: TodoListViewModel + + private enum Constants { + static let apiURL = "https://jsonplaceholder.typicode.com" + } + + init() { + let apiClient = WKAPIClient(baseURL: Constants.apiURL) + self.model = TodoListViewModel(apiClient: apiClient) + } + var body: some Scene { WindowGroup { - TodoListView() + TodoListView(viewModel: self.model) } } } diff --git a/docs/ExampleApp/WireKitSampleTests/WireKitSampleTests.swift b/docs/ExampleApp/WireKitSampleTests/WireKitSampleTests.swift new file mode 100644 index 0000000..4a38600 --- /dev/null +++ b/docs/ExampleApp/WireKitSampleTests/WireKitSampleTests.swift @@ -0,0 +1,35 @@ +// +// WireKitSampleTests.swift +// WireKitSampleTests +// +// Created by Daniel on 29/04/23. +// + +import XCTest + +final class WireKitSampleTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } + +}