From 6fc92a03950a0a030da968687d0ad8f338327b2a Mon Sep 17 00:00:00 2001 From: Igor Date: Fri, 25 Oct 2024 09:12:21 +0200 Subject: [PATCH 1/8] fix(GiniBankSDK): PP-138 alternative token source --- .../Documents/Core/Client.swift | 6 +++ ...niBankNetworkingScreenApiCoordinator.swift | 40 +++++++++++++++++++ .../Core/Networking/GiniBank+Networking.swift | 33 +++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Client.swift b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Client.swift index e4b7854fb..3c6986668 100644 --- a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Client.swift +++ b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Client.swift @@ -24,3 +24,9 @@ public struct Client { self.domain = domain } } + +public protocol TokenSource { + var domain: String { get } + var id: String { get } + var secret: String { get } +} diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift index 3786b6b69..c80d92fbf 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift @@ -151,6 +151,26 @@ open class GiniBankNetworkingScreenApiCoordinator: GiniScreenAPICoordinator, Gin self.trackingDelegate = trackingDelegate } + public init(alternativeTokenSource tokenSource: TokenSource, + resultsDelegate: GiniCaptureResultsDelegate, + configuration: GiniBankConfiguration, + documentMetadata: Document.Metadata?, + api: APIDomain, + trackingDelegate: GiniCaptureTrackingDelegate?, + lib: GiniBankAPI) { + documentService = DocumentService(lib: lib, metadata: documentMetadata) + configurationService = lib.configurationService() + let captureConfiguration = configuration.captureConfiguration() + super.init(withDelegate: nil, giniConfiguration: captureConfiguration) + + visionDelegate = self + GiniBank.setConfiguration(configuration) + giniBankConfiguration = configuration + giniBankConfiguration.documentService = documentService + self.resultsDelegate = resultsDelegate + self.trackingDelegate = trackingDelegate + } + public init(resultsDelegate: GiniCaptureResultsDelegate, configuration: GiniBankConfiguration, documentMetadata: Document.Metadata?, @@ -193,6 +213,26 @@ open class GiniBankNetworkingScreenApiCoordinator: GiniScreenAPICoordinator, Gin lib: lib) } + convenience init(alternativeTokenSource tokenSource: TokenSource, + resultsDelegate: GiniCaptureResultsDelegate, + configuration: GiniBankConfiguration, + documentMetadata: Document.Metadata?, + api: APIDomain, + userApi: UserDomain, + trackingDelegate: GiniCaptureTrackingDelegate?) { + let lib = GiniBankAPI + .Builder(client: Client(id: tokenSource.id, secret: tokenSource.secret, domain: tokenSource.domain), api: api, userApi: userApi) + .build() + + self.init(alternativeTokenSource: tokenSource, + resultsDelegate: resultsDelegate, + configuration: configuration, + documentMetadata: documentMetadata, + api: api, + trackingDelegate: trackingDelegate, + lib: lib) + } + private func deliver(result: ExtractionResult, analysisDelegate: AnalysisDelegate) { let hasExtractions = result.extractions.count > 0 diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift index 566927e8b..9fd2bd8a8 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift @@ -46,6 +46,39 @@ extension GiniBank { return screenCoordinator.startSDK(withDocuments: importedDocuments) } + /** + Returns a view controller which will handle the analysis process. + It's the easiest way to get started with the Gini Bank SDK as it comes pre-configured and handles + all screens and transitions out of the box, including the networking. + + - parameter alternativeTokenSource: Alternative token source + - parameter resultsDelegate: Results delegate object where you can get the results of the analysis. + - parameter configuration: The configuration to set. + - parameter documentMetadata: Additional HTTP headers to send when uploading documents + - parameter api: The Gini backend API to use. Supply .custom("domain") in order to specify a custom domain. + - parameter userApi: The Gini user backend API to use. Supply .custom("domain") in order to specify a custom domain. + - parameter trackingDelegate: A delegate object to receive user events + + - returns: A presentable view controller. + */ + public class func viewController(withAlternativeTokenSource tokenSource: TokenSource, + importedDocuments: [GiniCaptureDocument]? = nil, + configuration: GiniBankConfiguration, + resultsDelegate: GiniCaptureResultsDelegate, + documentMetadata: Document.Metadata? = nil, + api: APIDomain = .default, + userApi: UserDomain = .default, + trackingDelegate: GiniCaptureTrackingDelegate? = nil) -> UIViewController { + let screenCoordinator = GiniBankNetworkingScreenApiCoordinator(alternativeTokenSource: tokenSource, + resultsDelegate: resultsDelegate, + configuration: configuration, + documentMetadata: documentMetadata, + api: api, + userApi: userApi, + trackingDelegate: trackingDelegate) + return screenCoordinator.startSDK(withDocuments: importedDocuments) + } + // MARK: - Screen API with Custom Networking - Initializers for 'UIViewController' /** From 2ba39aab05646b226c7bcd0f5855065b3dba8f72 Mon Sep 17 00:00:00 2001 From: Igor Date: Thu, 31 Oct 2024 09:40:32 +0100 Subject: [PATCH 2/8] fix(GiniBankSDK): PP-142 fix alternative token source --- .../GiniBankAPILibrary/Documents/Core/Client.swift | 6 ------ .../Documents/Core/GiniBankAPI.swift | 2 +- .../GiniBankNetworkingScreenApiCoordinator.swift | 14 ++++---------- .../Core/Networking/GiniBank+Networking.swift | 8 +------- 4 files changed, 6 insertions(+), 24 deletions(-) diff --git a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Client.swift b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Client.swift index 3c6986668..e4b7854fb 100644 --- a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Client.swift +++ b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Client.swift @@ -24,9 +24,3 @@ public struct Client { self.domain = domain } } - -public protocol TokenSource { - var domain: String { get } - var id: String { get } - var secret: String { get } -} diff --git a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift index e1014049f..825ac7370 100644 --- a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift +++ b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift @@ -92,7 +92,7 @@ extension GiniBankAPI { /** * Creates a Gini Bank API Library to be used with a transparent proxy and a custom api access token source. */ - public init(customApiDomain: String, + public init(customApiDomain: String = "pay-api.gini.net", alternativeTokenSource: AlternativeTokenSource, logLevel: LogLevel = .none, sessionDelegate: URLSessionDelegate? = nil) { diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift index c80d92fbf..0d1f4b195 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift @@ -151,11 +151,9 @@ open class GiniBankNetworkingScreenApiCoordinator: GiniScreenAPICoordinator, Gin self.trackingDelegate = trackingDelegate } - public init(alternativeTokenSource tokenSource: TokenSource, - resultsDelegate: GiniCaptureResultsDelegate, + public init(resultsDelegate: GiniCaptureResultsDelegate, configuration: GiniBankConfiguration, documentMetadata: Document.Metadata?, - api: APIDomain, trackingDelegate: GiniCaptureTrackingDelegate?, lib: GiniBankAPI) { documentService = DocumentService(lib: lib, metadata: documentMetadata) @@ -213,22 +211,18 @@ open class GiniBankNetworkingScreenApiCoordinator: GiniScreenAPICoordinator, Gin lib: lib) } - convenience init(alternativeTokenSource tokenSource: TokenSource, + convenience init(alternativeTokenSource tokenSource: AlternativeTokenSource, resultsDelegate: GiniCaptureResultsDelegate, configuration: GiniBankConfiguration, documentMetadata: Document.Metadata?, - api: APIDomain, - userApi: UserDomain, trackingDelegate: GiniCaptureTrackingDelegate?) { let lib = GiniBankAPI - .Builder(client: Client(id: tokenSource.id, secret: tokenSource.secret, domain: tokenSource.domain), api: api, userApi: userApi) + .Builder(alternativeTokenSource: tokenSource) .build() - self.init(alternativeTokenSource: tokenSource, - resultsDelegate: resultsDelegate, + self.init(resultsDelegate: resultsDelegate, configuration: configuration, documentMetadata: documentMetadata, - api: api, trackingDelegate: trackingDelegate, lib: lib) } diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift index 9fd2bd8a8..836eb24d9 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift @@ -55,26 +55,20 @@ extension GiniBank { - parameter resultsDelegate: Results delegate object where you can get the results of the analysis. - parameter configuration: The configuration to set. - parameter documentMetadata: Additional HTTP headers to send when uploading documents - - parameter api: The Gini backend API to use. Supply .custom("domain") in order to specify a custom domain. - - parameter userApi: The Gini user backend API to use. Supply .custom("domain") in order to specify a custom domain. - parameter trackingDelegate: A delegate object to receive user events - returns: A presentable view controller. */ - public class func viewController(withAlternativeTokenSource tokenSource: TokenSource, + public class func viewController(withAlternativeTokenSource tokenSource: AlternativeTokenSource, importedDocuments: [GiniCaptureDocument]? = nil, configuration: GiniBankConfiguration, resultsDelegate: GiniCaptureResultsDelegate, documentMetadata: Document.Metadata? = nil, - api: APIDomain = .default, - userApi: UserDomain = .default, trackingDelegate: GiniCaptureTrackingDelegate? = nil) -> UIViewController { let screenCoordinator = GiniBankNetworkingScreenApiCoordinator(alternativeTokenSource: tokenSource, resultsDelegate: resultsDelegate, configuration: configuration, documentMetadata: documentMetadata, - api: api, - userApi: userApi, trackingDelegate: trackingDelegate) return screenCoordinator.startSDK(withDocuments: importedDocuments) } From 852b7282623628de53b9169d7a4961bc7bee1548 Mon Sep 17 00:00:00 2001 From: Igor Date: Thu, 7 Nov 2024 11:41:51 +0100 Subject: [PATCH 3/8] fix(GiniBankSDK): PP-142 make method private --- .../Core/GiniBankNetworkingScreenApiCoordinator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift index 0d1f4b195..6b598c322 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/GiniBankNetworkingScreenApiCoordinator.swift @@ -151,7 +151,7 @@ open class GiniBankNetworkingScreenApiCoordinator: GiniScreenAPICoordinator, Gin self.trackingDelegate = trackingDelegate } - public init(resultsDelegate: GiniCaptureResultsDelegate, + private init(resultsDelegate: GiniCaptureResultsDelegate, configuration: GiniBankConfiguration, documentMetadata: Document.Metadata?, trackingDelegate: GiniCaptureTrackingDelegate?, From 36220fdff12545c8b6aa88c01490e66dec841ee4 Mon Sep 17 00:00:00 2001 From: Igor Date: Mon, 11 Nov 2024 13:12:07 +0100 Subject: [PATCH 4/8] fix(GiniBankSDK): PP-142 pr comment --- .../Sources/GiniBankAPILibrary/Documents/APIResource.swift | 2 +- .../Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/APIResource.swift b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/APIResource.swift index 952fb6e79..5cd4e0188 100644 --- a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/APIResource.swift +++ b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/APIResource.swift @@ -13,7 +13,7 @@ public enum APIDomain { /// A custom domain with optional path and custom token source case custom(domain: String, path: String? = nil, tokenSource: AlternativeTokenSource?) - var domainString: String { + public var domainString: String { switch self { case .default: return "pay-api.gini.net" case .custom(let domain, _, _): return domain diff --git a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift index 825ac7370..d65d943d8 100644 --- a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift +++ b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift @@ -92,7 +92,7 @@ extension GiniBankAPI { /** * Creates a Gini Bank API Library to be used with a transparent proxy and a custom api access token source. */ - public init(customApiDomain: String = "pay-api.gini.net", + public init(customApiDomain: String = APIDomain.default.domainString, alternativeTokenSource: AlternativeTokenSource, logLevel: LogLevel = .none, sessionDelegate: URLSessionDelegate? = nil) { From 4404d7e3a1d0ab76fc5f7f576b026fec3a9c5183 Mon Sep 17 00:00:00 2001 From: Nadya Karaban Date: Wed, 20 Nov 2024 15:42:20 +0100 Subject: [PATCH 5/8] fix(GiniBankAPILibrary): Update test, since resolved payment can't be resolved again --- .../GiniBankAPILibraryExampleTests/IntegrationTests.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BankAPILibrary/GiniBankAPILibraryExample/GiniBankAPILibraryExampleTests/IntegrationTests.swift b/BankAPILibrary/GiniBankAPILibraryExample/GiniBankAPILibraryExampleTests/IntegrationTests.swift index caf3a6696..7cc7c5daf 100644 --- a/BankAPILibrary/GiniBankAPILibraryExample/GiniBankAPILibraryExampleTests/IntegrationTests.swift +++ b/BankAPILibrary/GiniBankAPILibraryExample/GiniBankAPILibraryExampleTests/IntegrationTests.swift @@ -75,16 +75,16 @@ class IntegrationTests: XCTestCase { } func testResolvePaymentRequest(){ - let expect = expectation(description: "it resolves the payment request") + let message = "You can't resolve the previously resolved payment request" + let expect = expectation(description: message) let paymentService = giniBankAPILib.paymentService() paymentService.resolvePaymentRequest(id: paymentRequestID, recipient: "Dr. med. Hackler", iban: "DE13760700120500154000", bic: "", amount: "335.50:EUR", purpose: "ReNr AZ356789Z"){ result in switch result { case .success(let resolvedRequest): - XCTAssertEqual(resolvedRequest.links?.payment, "https://pay-api.gini.net/paymentRequests/a6466506-acf1-4896-94c8-9b398d4e0ee1/payment") - expect.fulfill() + XCTFail(message) case .failure(let error): - XCTFail(String(describing: error)) + expect.fulfill() } } wait(for: [expect], timeout: 10) From d66590595703abfef7f3b508cfe316288cecd32c Mon Sep 17 00:00:00 2001 From: Nadya Karaban Date: Wed, 20 Nov 2024 16:57:15 +0100 Subject: [PATCH 6/8] fix(GiniBankAPILibraryPinning): Update test, since resolved payment can't be resolved again --- .../GiniBankAPILibraryPinningIntegrationTests.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/BankAPILibrary/GiniBankAPILibraryPinningExample/GiniBankAPILibraryPinningExampleTests/GiniBankAPILibraryPinningIntegrationTests.swift b/BankAPILibrary/GiniBankAPILibraryPinningExample/GiniBankAPILibraryPinningExampleTests/GiniBankAPILibraryPinningIntegrationTests.swift index 2e4d17423..faca539f4 100644 --- a/BankAPILibrary/GiniBankAPILibraryPinningExample/GiniBankAPILibraryPinningExampleTests/GiniBankAPILibraryPinningIntegrationTests.swift +++ b/BankAPILibrary/GiniBankAPILibraryPinningExample/GiniBankAPILibraryPinningExampleTests/GiniBankAPILibraryPinningIntegrationTests.swift @@ -89,16 +89,16 @@ class PinningIntegrationTests: XCTestCase { } func testResolvePaymentRequest(){ - let expect = expectation(description: "it resolves the payment request") + let message = "You can't resolve the previously resolved payment request" + let expect = expectation(description: message) let paymentService = giniBankAPILib.paymentService() paymentService.resolvePaymentRequest(id: paymentRequestID, recipient: "Dr. med. Hackler", iban: "DE13760700120500154000", bic: "", amount: "335.50:EUR", purpose: "ReNr AZ356789Z"){ result in switch result { - case .success(let resolvedRequest): - XCTAssertEqual(resolvedRequest.links?.payment, "https://pay-api.gini.net/paymentRequests/a6466506-acf1-4896-94c8-9b398d4e0ee1/payment") - expect.fulfill() - case .failure(let error): - XCTFail(String(describing: error)) + case .success(let resolvedRequest): + XCTFail(message) + case .failure(let error): + expect.fulfill() } } wait(for: [expect], timeout: 10) From 02122faa92b1cbaa10046f545c02b8779c9c4ab9 Mon Sep 17 00:00:00 2001 From: Igor Date: Thu, 21 Nov 2024 10:21:04 +0100 Subject: [PATCH 7/8] fix(GiniBankSDK): Add tests and adjust PR comments PP-142 --- .../Documents/Core/Auth/Token.swift | 13 +- .../Documents/Core/GiniBankAPI.swift | 8 + .../Core/Networking/GiniBank+Networking.swift | 4 +- .../NetworkingScreenApiCoordinatorTests.swift | 150 ++++++++++++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 BankSDK/GiniBankSDK/Tests/GiniBankSDKTests/NetworkingScreenApiCoordinatorTests.swift diff --git a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Auth/Token.swift b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Auth/Token.swift index 34e177a9f..e002bba6e 100644 --- a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Auth/Token.swift +++ b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/Auth/Token.swift @@ -7,8 +7,7 @@ import Foundation -public final class Token { - +public final class Token: Hashable { var expiration: Date var scope: String? var type: String? @@ -28,6 +27,16 @@ public final class Token { case accessToken = "access_token" } + public static func == (lhs: Token, rhs: Token) -> Bool { + lhs.hashValue == rhs.hashValue + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(expiration) + hasher.combine(scope) + hasher.combine(type) + hasher.combine(accessToken) + } } extension Token: Decodable { diff --git a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift index d65d943d8..b199b2ff5 100644 --- a/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift +++ b/BankAPILibrary/GiniBankAPILibrary/Sources/GiniBankAPILibrary/Documents/Core/GiniBankAPI.swift @@ -134,6 +134,7 @@ extension GiniBankAPI { } private func save(_ client: Client) { + guard !runningUnitTests() else { return } do { try KeychainStore().save(item: KeychainManagerItem(key: .clientId, value: client.id, @@ -149,5 +150,12 @@ extension GiniBankAPI { "Check that the Keychain capability is enabled in your project") } } + + private func runningUnitTests() -> Bool { + #if canImport(XCTest) + return ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil + #endif + return false + } } } diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift index 836eb24d9..e3f5d28ca 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Networking/GiniBank+Networking.swift @@ -19,6 +19,7 @@ extension GiniBank { all screens and transitions out of the box, including the networking. - parameter client: `GiniClient` with the information needed to enable document analysis + - parameter importedDocuments: There should be either images or one PDF, and they should be validated before calling this method. - parameter resultsDelegate: Results delegate object where you can get the results of the analysis. - parameter configuration: The configuration to set. - parameter documentMetadata: Additional HTTP headers to send when uploading documents @@ -51,7 +52,8 @@ extension GiniBank { It's the easiest way to get started with the Gini Bank SDK as it comes pre-configured and handles all screens and transitions out of the box, including the networking. - - parameter alternativeTokenSource: Alternative token source + - parameter tokenSource: Alternative token source + - parameter importedDocuments: There should be either images or one PDF, and they should be validated before calling this method. - parameter resultsDelegate: Results delegate object where you can get the results of the analysis. - parameter configuration: The configuration to set. - parameter documentMetadata: Additional HTTP headers to send when uploading documents diff --git a/BankSDK/GiniBankSDK/Tests/GiniBankSDKTests/NetworkingScreenApiCoordinatorTests.swift b/BankSDK/GiniBankSDK/Tests/GiniBankSDKTests/NetworkingScreenApiCoordinatorTests.swift new file mode 100644 index 000000000..fb30fb195 --- /dev/null +++ b/BankSDK/GiniBankSDK/Tests/GiniBankSDKTests/NetworkingScreenApiCoordinatorTests.swift @@ -0,0 +1,150 @@ +// +// NetworkingScreenApiCoordinatorTests.swift +// +// Copyright © 2024 Gini GmbH. All rights reserved. +// + +@testable import GiniBankAPILibrary +@testable import GiniBankSDK +@testable import GiniCaptureSDK +import XCTest + +private class MockTokenSource: AlternativeTokenSource { + var tokenToReturn: Token? + func fetchToken(completion: @escaping (Result) -> Void) { + if let tokenToReturn { + completion(.success(tokenToReturn)) + } else { + completion(.failure(.requestCancelled)) + } + } +} + +private class MockCaptureResultsDelegate: GiniCaptureResultsDelegate { + func giniCaptureAnalysisDidFinishWith(result: AnalysisResult) { + } + + func giniCaptureDidCancelAnalysis() { + } + + func giniCaptureDidEnterManually() { + } +} + +private class MockTrackingDelegate: GiniCaptureTrackingDelegate { + func onOnboardingScreenEvent(event: Event) { + } + + func onCameraScreenEvent(event: Event) { + } + + func onReviewScreenEvent(event: Event) { + } + + func onAnalysisScreenEvent(event: Event) { + } +} + +final class NetworkingScreenApiCoordinatorTests: XCTestCase { + + func testInitWithAlternativeTokenSource() throws { + /// ready + let source = MockTokenSource() + let testToken = Token(expiration: .init(), scope: "scope", type: "type", accessToken: "some_totally_random_gibberish") + source.tokenToReturn = testToken + let resultsDelegate = MockCaptureResultsDelegate() + let cfg = GiniBankConfiguration() + let metadata = Document.Metadata(branchId: "branch") + let trackingDelegate = MockTrackingDelegate() + + /// set + let coord = GiniBankNetworkingScreenApiCoordinator(alternativeTokenSource: source, resultsDelegate: resultsDelegate, configuration: cfg, documentMetadata: metadata, trackingDelegate: trackingDelegate) + let service = try XCTUnwrap( + ( + (coord.documentService as? GiniCaptureSDK.DocumentService)? + .captureNetworkService as? DefaultCaptureNetworkService + )?.documentService + ) + + /// test + + // check default api domain + XCTAssertEqual(service.apiDomain.domainString, "pay-api.gini.net") + + // check for correct token + let logInExpectation = self.expectation(description: "login") + var receivedTokenOptional: Token? + service.sessionManager.logIn { result in + switch result { + case .success(let token): + receivedTokenOptional = token + logInExpectation.fulfill() + case .failure(let error): + XCTFail("Failure: \(error.localizedDescription)") + } + } + wait(for: [logInExpectation], timeout: 1) + + let receivedToken = try XCTUnwrap(receivedTokenOptional) + XCTAssertEqual(receivedToken, testToken) + + // check for delegates/configs + XCTAssertNotNil(coord.resultsDelegate as? MockCaptureResultsDelegate) + XCTAssertEqual(coord.giniBankConfiguration, cfg) + XCTAssertNotNil(coord.trackingDelegate as? MockTrackingDelegate) + XCTAssertEqual(coord.documentService.metadata?.headers[Document.Metadata.headerKeyPrefix + Document.Metadata.branchIdHeaderKey], "branch") + } + + func testViewControllerWithAlternativeTokenSource() throws { + /// ready + let source = MockTokenSource() + let testToken = Token(expiration: .init(), scope: "scope", type: "type", accessToken: "some_totally_random_gibberish") + source.tokenToReturn = testToken + let resultsDelegate = MockCaptureResultsDelegate() + let cfg = GiniBankConfiguration() + let metadata = Document.Metadata(branchId: "branch") + let trackingDelegate = MockTrackingDelegate() + + /// set + let vc = try XCTUnwrap( + GiniBank.viewController(withAlternativeTokenSource: source, configuration: cfg, resultsDelegate: resultsDelegate, documentMetadata: metadata, trackingDelegate: trackingDelegate) as? ContainerNavigationController + ) + let coord = try XCTUnwrap( + vc.coordinator as? GiniBankNetworkingScreenApiCoordinator + ) + let service = try XCTUnwrap( + ( + (coord.documentService as? GiniCaptureSDK.DocumentService)? + .captureNetworkService as? DefaultCaptureNetworkService + )?.documentService + ) + + /// test + + // check default api domain + XCTAssertEqual(service.apiDomain.domainString, "pay-api.gini.net") + + // check for correct token + let logInExpectation = self.expectation(description: "login") + var receivedTokenOptional: Token? + service.sessionManager.logIn { result in + switch result { + case .success(let token): + receivedTokenOptional = token + logInExpectation.fulfill() + case .failure(let error): + XCTFail("Failure: \(error.localizedDescription)") + } + } + wait(for: [logInExpectation], timeout: 1) + + let receivedToken = try XCTUnwrap(receivedTokenOptional) + XCTAssertEqual(receivedToken, testToken) + + // check for delegates/configs + XCTAssertNotNil(coord.resultsDelegate as? MockCaptureResultsDelegate) + XCTAssertEqual(coord.giniBankConfiguration, cfg) + XCTAssertNotNil(coord.trackingDelegate as? MockTrackingDelegate) + XCTAssertEqual(coord.documentService.metadata?.headers[Document.Metadata.headerKeyPrefix + Document.Metadata.branchIdHeaderKey], "branch") + } +} From 64f2d3cf65f6c4af4b14aee017f5063539f06f19 Mon Sep 17 00:00:00 2001 From: Igor Date: Fri, 22 Nov 2024 16:23:33 +0100 Subject: [PATCH 8/8] fix(GiniBankSDK): Fix naming inside tests and add fail reasons PP-138 --- .../NetworkingScreenApiCoordinatorTests.swift | 188 +++++++++++------- 1 file changed, 112 insertions(+), 76 deletions(-) diff --git a/BankSDK/GiniBankSDK/Tests/GiniBankSDKTests/NetworkingScreenApiCoordinatorTests.swift b/BankSDK/GiniBankSDK/Tests/GiniBankSDKTests/NetworkingScreenApiCoordinatorTests.swift index fb30fb195..b0f61e951 100644 --- a/BankSDK/GiniBankSDK/Tests/GiniBankSDKTests/NetworkingScreenApiCoordinatorTests.swift +++ b/BankSDK/GiniBankSDK/Tests/GiniBankSDKTests/NetworkingScreenApiCoordinatorTests.swift @@ -10,10 +10,13 @@ import XCTest private class MockTokenSource: AlternativeTokenSource { - var tokenToReturn: Token? + var token: Token? + init(token: Token? = nil) { + self.token = token + } func fetchToken(completion: @escaping (Result) -> Void) { - if let tokenToReturn { - completion(.success(tokenToReturn)) + if let token { + completion(.success(token)) } else { completion(.failure(.requestCancelled)) } @@ -46,105 +49,138 @@ private class MockTrackingDelegate: GiniCaptureTrackingDelegate { } final class NetworkingScreenApiCoordinatorTests: XCTestCase { + private var tokenSource: MockTokenSource! + private var resultsDelegate: MockCaptureResultsDelegate! + private var configuration: GiniBankConfiguration! + private var metadata: Document.Metadata! + private var trackingDelegate: MockTrackingDelegate! + + override func setUp() { + tokenSource = makeTokenSource() + resultsDelegate = MockCaptureResultsDelegate() + configuration = GiniBankConfiguration() + metadata = Document.Metadata(branchId: "branch") + trackingDelegate = MockTrackingDelegate() + } func testInitWithAlternativeTokenSource() throws { - /// ready - let source = MockTokenSource() - let testToken = Token(expiration: .init(), scope: "scope", type: "type", accessToken: "some_totally_random_gibberish") - source.tokenToReturn = testToken - let resultsDelegate = MockCaptureResultsDelegate() - let cfg = GiniBankConfiguration() - let metadata = Document.Metadata(branchId: "branch") - let trackingDelegate = MockTrackingDelegate() - - /// set - let coord = GiniBankNetworkingScreenApiCoordinator(alternativeTokenSource: source, resultsDelegate: resultsDelegate, configuration: cfg, documentMetadata: metadata, trackingDelegate: trackingDelegate) - let service = try XCTUnwrap( - ( - (coord.documentService as? GiniCaptureSDK.DocumentService)? - .captureNetworkService as? DefaultCaptureNetworkService - )?.documentService + let (coordinator, service) = try makeCoordinatorAndService() + + // check domain + XCTAssertEqual(service.apiDomain.domainString, "pay-api.gini.net", "Service api domain should match our default") + + // check token + let receivedToken = try XCTUnwrap( + login(service: service), + "Should log in successfully" ) + XCTAssertEqual(receivedToken, tokenSource.token, "Received token should match the expected token") - /// test + // check for delegates/configs + XCTAssertNotNil( + coordinator.resultsDelegate as? MockCaptureResultsDelegate, + "Coordinator should have correct results delegate instance" + ) + XCTAssertEqual(coordinator.giniBankConfiguration, configuration, "Coordinator should have correct configuration instance") + XCTAssertNotNil( + coordinator.trackingDelegate as? MockTrackingDelegate, + "Coordinator should have correct tracking delegate instance" + ) + XCTAssertEqual(coordinator.documentService.metadata?.headers, metadata.headers, "Metadata headers should match") + } - // check default api domain - XCTAssertEqual(service.apiDomain.domainString, "pay-api.gini.net") + func testViewControllerWithAlternativeTokenSource() throws { + let (coordinator, service) = try makeCoordinatorAndService(fromViewController: true) - // check for correct token - let logInExpectation = self.expectation(description: "login") - var receivedTokenOptional: Token? - service.sessionManager.logIn { result in - switch result { - case .success(let token): - receivedTokenOptional = token - logInExpectation.fulfill() - case .failure(let error): - XCTFail("Failure: \(error.localizedDescription)") - } - } - wait(for: [logInExpectation], timeout: 1) + // check domain + XCTAssertEqual(service.apiDomain.domainString, "pay-api.gini.net", "Service api domain should match our default") - let receivedToken = try XCTUnwrap(receivedTokenOptional) - XCTAssertEqual(receivedToken, testToken) + // check token + let receivedToken = try XCTUnwrap( + login(service: service), + "Should log in successfully" + ) + XCTAssertEqual(receivedToken, tokenSource.token, "Received token should match the expected token") // check for delegates/configs - XCTAssertNotNil(coord.resultsDelegate as? MockCaptureResultsDelegate) - XCTAssertEqual(coord.giniBankConfiguration, cfg) - XCTAssertNotNil(coord.trackingDelegate as? MockTrackingDelegate) - XCTAssertEqual(coord.documentService.metadata?.headers[Document.Metadata.headerKeyPrefix + Document.Metadata.branchIdHeaderKey], "branch") + XCTAssertNotNil( + coordinator.resultsDelegate as? MockCaptureResultsDelegate, + "Coordinator should have correct results delegate instance" + ) + XCTAssertEqual(coordinator.giniBankConfiguration, configuration, "Coordinator should have correct configuration instance") + XCTAssertNotNil( + coordinator.trackingDelegate as? MockTrackingDelegate, + "Coordinator should have correct tracking delegate instance" + ) + XCTAssertEqual(coordinator.documentService.metadata?.headers, metadata.headers, "Metadata headers should match") } +} - func testViewControllerWithAlternativeTokenSource() throws { - /// ready - let source = MockTokenSource() - let testToken = Token(expiration: .init(), scope: "scope", type: "type", accessToken: "some_totally_random_gibberish") - source.tokenToReturn = testToken - let resultsDelegate = MockCaptureResultsDelegate() - let cfg = GiniBankConfiguration() - let metadata = Document.Metadata(branchId: "branch") - let trackingDelegate = MockTrackingDelegate() - - /// set - let vc = try XCTUnwrap( - GiniBank.viewController(withAlternativeTokenSource: source, configuration: cfg, resultsDelegate: resultsDelegate, documentMetadata: metadata, trackingDelegate: trackingDelegate) as? ContainerNavigationController +private extension NetworkingScreenApiCoordinatorTests { + func makeTokenSource() -> MockTokenSource { + MockTokenSource( + token: + Token( + expiration: .init(), + scope: "the_scope", + type: "the_type", + accessToken: "some_totally_random_gibberish" + ) ) - let coord = try XCTUnwrap( - vc.coordinator as? GiniBankNetworkingScreenApiCoordinator + } + + func makeCoordinatorAndService(fromViewController: Bool = false) throws -> (GiniBankNetworkingScreenApiCoordinator, DefaultDocumentService) { + let coordinator: GiniBankNetworkingScreenApiCoordinator + if fromViewController { + let viewController = try XCTUnwrap( + GiniBank.viewController( + withAlternativeTokenSource: tokenSource, + configuration: configuration, + resultsDelegate: resultsDelegate, + documentMetadata: metadata, + trackingDelegate: trackingDelegate + ) as? ContainerNavigationController, + "There should be an instance of `ContainerNavigationController`" + ) + coordinator = try XCTUnwrap( + viewController.coordinator as? GiniBankNetworkingScreenApiCoordinator, + "The instance of `ContainerNavigationController` should have a coordinator of type `GiniBankNetworkingScreenApiCoordinator" + ) + } else { + coordinator = GiniBankNetworkingScreenApiCoordinator( + alternativeTokenSource: tokenSource, + resultsDelegate: resultsDelegate, + configuration: configuration, + documentMetadata: metadata, + trackingDelegate: trackingDelegate + ) + } + let documentService = try XCTUnwrap( + coordinator.documentService as? GiniCaptureSDK.DocumentService, + "The coordinator should have a document service of type `GiniCaptureSDK.DocumentService" ) - let service = try XCTUnwrap( - ( - (coord.documentService as? GiniCaptureSDK.DocumentService)? - .captureNetworkService as? DefaultCaptureNetworkService - )?.documentService + let captureNetworkService = try XCTUnwrap( + documentService.captureNetworkService as? DefaultCaptureNetworkService, + "The document service should have a capture network service of type `DefaultCaptureNetworkService" ) - /// test - // check default api domain - XCTAssertEqual(service.apiDomain.domainString, "pay-api.gini.net") + return (coordinator, captureNetworkService.documentService) + } - // check for correct token + func login(service: DefaultDocumentService) throws -> Token? { let logInExpectation = self.expectation(description: "login") - var receivedTokenOptional: Token? + var receivedToken: Token? service.sessionManager.logIn { result in switch result { case .success(let token): - receivedTokenOptional = token + receivedToken = token logInExpectation.fulfill() case .failure(let error): XCTFail("Failure: \(error.localizedDescription)") } } wait(for: [logInExpectation], timeout: 1) - - let receivedToken = try XCTUnwrap(receivedTokenOptional) - XCTAssertEqual(receivedToken, testToken) - - // check for delegates/configs - XCTAssertNotNil(coord.resultsDelegate as? MockCaptureResultsDelegate) - XCTAssertEqual(coord.giniBankConfiguration, cfg) - XCTAssertNotNil(coord.trackingDelegate as? MockTrackingDelegate) - XCTAssertEqual(coord.documentService.metadata?.headers[Document.Metadata.headerKeyPrefix + Document.Metadata.branchIdHeaderKey], "branch") + return receivedToken } }