From 434bfdd4dc8911076cc608eb18910c24ffe85fbd Mon Sep 17 00:00:00 2001 From: Josh Heald Date: Fri, 13 Jan 2023 17:14:24 +0000 Subject: [PATCH 1/2] 8290 Update tests to simplify adding dependency --- .../Stores/CardPresentPaymentStoreTests.swift | 172 +++--------------- 1 file changed, 25 insertions(+), 147 deletions(-) diff --git a/Yosemite/YosemiteTests/Stores/CardPresentPaymentStoreTests.swift b/Yosemite/YosemiteTests/Stores/CardPresentPaymentStoreTests.swift index 98b566caf3e..dc3a209659c 100644 --- a/Yosemite/YosemiteTests/Stores/CardPresentPaymentStoreTests.swift +++ b/Yosemite/YosemiteTests/Stores/CardPresentPaymentStoreTests.swift @@ -32,6 +32,8 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// Mock Card Reader Service: In memory private var mockCardReaderService: MockCardReaderService! + private var cardPresentStore: CardPresentPaymentStore! + /// Dummy Site ID /// private let sampleSiteID: Int64 = 1234 @@ -66,6 +68,11 @@ final class CardPresentPaymentStoreTests: XCTestCase { storageManager = MockStorageManager() network = MockNetwork() mockCardReaderService = MockCardReaderService() + mockCardReaderConfigProvider = MockCommonReaderConfigProviding() + cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, + storageManager: storageManager, + network: network, + cardReaderService: mockCardReaderService) } override func tearDown() { @@ -82,11 +89,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// Verifies that CardPresentPaymentAction.startCardReaderDiscovery hits the `start` method in the service. /// func test_start_discovery_action_hits_start_in_service() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let action = CardPresentPaymentAction.startCardReaderDiscovery( siteID: sampleSiteID, discoveryMethod: .bluetoothScan, @@ -98,11 +100,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_start_discovery_action_returns_data_eventually() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let expectation = self.expectation(description: "Readers discovered") let action = CardPresentPaymentAction.startCardReaderDiscovery( @@ -120,11 +117,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_start_discovery_action_passes_configuration_provider_to_service() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let action = CardPresentPaymentAction.startCardReaderDiscovery(siteID: sampleSiteID, discoveryMethod: .bluetoothScan, onReaderDiscovered: { _ in }, @@ -136,11 +128,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_start_discovery_action_passes_discovery_method_to_service() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let action = CardPresentPaymentAction.startCardReaderDiscovery(siteID: sampleSiteID, discoveryMethod: .bluetoothScan, onReaderDiscovered: { _ in }, @@ -161,11 +148,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { func test_start_discovery_action_returns_empty_error_when_token_fetching_fails() { let expectation = self.expectation(description: "Empty readers on failure to obtain a connection token") - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - network.simulateResponse(requestUrlSuffix: "payments/connection_tokens", filename: "generic_error") let action = CardPresentPaymentAction.startCardReaderDiscovery( @@ -186,11 +168,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_cancel_discovery_action_hits_cancel_in_service() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let action = CardPresentPaymentAction.cancelCardReaderDiscovery { result in // } @@ -203,11 +180,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// We are still not handling errors, so we will need a new test here /// for the case when cancelation fails, which apparently is a thing func test_cancel_discovery_action_publishes_idle_as_new_discovery_status() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let expectation = self.expectation(description: "Cancelling discovery published idle as discoveryStatus") let action = CardPresentPaymentAction.cancelCardReaderDiscovery { result in @@ -222,11 +194,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_cancel_discovery_after_start_rdpchanges_discovery_status_to_idle_eventually() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let expectation = self.expectation(description: "Cancelling discovery changes discoveryStatus to idle") let startDiscoveryAction = CardPresentPaymentAction.startCardReaderDiscovery( @@ -250,11 +217,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_connect_to_reader_action_updates_returns_provided_reader_on_success() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let expectation = self.expectation(description: "Connect to card reader") let reader = MockCardReader.bbposChipper2XBT() @@ -275,11 +237,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_disconnect_action_hits_disconnect_in_service() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let action = CardPresentPaymentAction.disconnect(onCompletion: { result in // }) @@ -292,10 +249,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// Verifies that the PaymentGatewayAccountStore hits the network when loading a WCPay Account and places nothing in storage in case of error. /// func test_loadAccounts_handles_failure() throws { - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) let expectation = self.expectation(description: "Load Account error response") network.simulateResponse(requestUrlSuffix: "payments/accounts", filename: "generic_error") @@ -307,7 +260,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { expectation.fulfill() }) - store.onAction(action) + cardPresentStore.onAction(action) wait(for: [expectation], timeout: Constants.expectationTimeout) XCTAssertNil(viewStorage.firstObject(ofType: Storage.PaymentGatewayAccount.self, matching: nil)) @@ -316,10 +269,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// Verifies that the PaymentGatewayAccountStore hits the network when loading a WCPay Account, propagates success and upserts the account into storage. /// func test_loadAccounts_returns_expected_data() throws { - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) let expectation = self.expectation(description: "Load Account fetch response") network.simulateResponse(requestUrlSuffix: "payments/accounts", filename: "wcpay-account-complete") @@ -330,7 +279,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { expectation.fulfill() }) - store.onAction(action) + cardPresentStore.onAction(action) wait(for: [expectation], timeout: Constants.expectationTimeout) XCTAssert(viewStorage.countObjects(ofType: Storage.PaymentGatewayAccount.self, matching: nil) == 2) @@ -348,11 +297,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// Verifies that the store hits the network when fetching a charge, and propagates success. /// func test_fetchWCPayCharge_returns_expected_data() throws { - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - network.simulateResponse(requestUrlSuffix: "payments/charges/\(sampleChargeID)", filename: "wcpay-charge-card-present") @@ -360,7 +304,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { let action = CardPresentPaymentAction.fetchWCPayCharge(siteID: self.sampleSiteID, chargeID: self.sampleChargeID, onCompletion: { result in promise(result) }) - store.onAction(action) + cardPresentStore.onAction(action) } XCTAssertTrue(result.isSuccess) let charge = try XCTUnwrap(result).get() @@ -368,11 +312,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_fetchWCPayCharge_inserts_charge_in_storage() throws { - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - network.simulateResponse(requestUrlSuffix: "payments/charges/\(sampleChargeID)", filename: "wcpay-charge-card-present") @@ -380,7 +319,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { let action = CardPresentPaymentAction.fetchWCPayCharge(siteID: self.sampleSiteID, chargeID: self.sampleChargeID, onCompletion: { result in promise(result) }) - store.onAction(action) + cardPresentStore.onAction(action) } XCTAssertTrue(result.isSuccess) @@ -394,11 +333,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_fetchWCPayCharge_inserts_card_present_charge_details_in_storage() throws { - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - network.simulateResponse(requestUrlSuffix: "payments/charges/\(sampleChargeID)", filename: "wcpay-charge-card-present") @@ -406,7 +340,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { let action = CardPresentPaymentAction.fetchWCPayCharge(siteID: self.sampleSiteID, chargeID: self.sampleChargeID, onCompletion: { result in promise(result) }) - store.onAction(action) + cardPresentStore.onAction(action) } XCTAssertTrue(result.isSuccess) @@ -425,11 +359,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_fetchWCPayCharge_inserts_card_charge_details_in_storage() throws { - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - network.simulateResponse(requestUrlSuffix: "payments/charges/\(sampleCardChargeID)", filename: "wcpay-charge-card") @@ -437,7 +366,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { let action = CardPresentPaymentAction.fetchWCPayCharge(siteID: self.sampleSiteID, chargeID: self.sampleCardChargeID, onCompletion: { result in promise(result) }) - store.onAction(action) + cardPresentStore.onAction(action) } XCTAssertTrue(result.isSuccess) @@ -455,11 +384,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_fetchWCPayCharge_inserts_interac_present_charge_details_in_storage() throws { - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - network.simulateResponse(requestUrlSuffix: "payments/charges/\(sampleInteracChargeID)", filename: "wcpay-charge-interac-present") @@ -467,7 +391,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { let action = CardPresentPaymentAction.fetchWCPayCharge(siteID: self.sampleSiteID, chargeID: self.sampleInteracChargeID, onCompletion: { result in promise(result) }) - store.onAction(action) + cardPresentStore.onAction(action) } XCTAssertTrue(result.isSuccess) @@ -488,18 +412,13 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// Verifies that the store hits the network when fetching a charge, and propagates errors. /// func test_fetchWCPayCharge_returns_error_on_failure() { - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - network.simulateResponse(requestUrlSuffix: "payments/charges/\(sampleErrorChargeID)", filename: "wcpay-charge-error") let result: Result = waitFor { [self] promise in let action = CardPresentPaymentAction.fetchWCPayCharge(siteID: self.sampleSiteID, chargeID: self.sampleErrorChargeID, onCompletion: { result in promise(result) }) - store.onAction(action) + cardPresentStore.onAction(action) } XCTAssertTrue(result.isFailure) } @@ -515,10 +434,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { otherCharge.update(with: otherNetworkCharge) XCTAssert(viewStorage.countObjects(ofType: Storage.WCPayCharge.self, matching: nil) == 2) - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) network.simulateResponse(requestUrlSuffix: "payments/charges/\(sampleErrorChargeID)", filename: "wcpay-charge-error") @@ -526,7 +441,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { let action = CardPresentPaymentAction.fetchWCPayCharge(siteID: self.sampleSiteID, chargeID: self.sampleErrorChargeID, onCompletion: { result in promise(result) }) - store.onAction(action) + cardPresentStore.onAction(action) } XCTAssertEqual(viewStorage.countObjects(ofType: Storage.WCPayCharge.self, matching: nil), 1) @@ -545,10 +460,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { otherCharge.update(with: otherNetworkCharge) XCTAssert(viewStorage.countObjects(ofType: Storage.WCPayCharge.self, matching: nil) == 2) - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) + network.simulateError(requestUrlSuffix: "payments/charges/\(sampleErrorChargeID)", error: DotcomError.unknown(code: "beep", message: "boop")) @@ -556,7 +468,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { let action = CardPresentPaymentAction.fetchWCPayCharge(siteID: self.sampleSiteID, chargeID: self.sampleErrorChargeID, onCompletion: { result in promise(result) }) - store.onAction(action) + cardPresentStore.onAction(action) } XCTAssertEqual(viewStorage.countObjects(ofType: Storage.WCPayCharge.self, matching: nil), 2) } @@ -568,10 +480,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// func test_collectPayment_calls_onProcessingCompletion_but_not_onCompletion_after_card_reader_capturePayment_success() { // Given - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) let intent = PaymentIntent.fake() mockCardReaderService.whenCapturingPayment(thenReturn: Just(intent) .setFailureType(to: Error.self) @@ -592,7 +500,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { } onCompletion: { result in XCTFail("Payment collection is not complete until the card removal step completes.") } - store.onAction(action) + cardPresentStore.onAction(action) } // Then @@ -605,10 +513,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// func test_collectPayment_calls_onCompletion_after_card_reader_capturePayment_success_and_card_removal_and_site_capturePayment() throws { // Given - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) let intent = PaymentIntent.fake() mockCardReaderService.whenCapturingPayment(thenReturn: Just(intent) .setFailureType(to: Error.self) @@ -629,7 +533,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { } onCompletion: { result in promise(result) } - store.onAction(action) + cardPresentStore.onAction(action) } // Then @@ -643,10 +547,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// func test_collectPayment_calls_onCompletion_with_failure_after_card_reader_capturePayment_success_but_site_capturePayment_failure() throws { // Given - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) let intent = PaymentIntent.fake() // Success on client-side processing. mockCardReaderService.whenCapturingPayment(thenReturn: Just(intent) @@ -669,7 +569,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { } onCompletion: { result in promise(result) } - store.onAction(action) + cardPresentStore.onAction(action) } // Then @@ -684,10 +584,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// func test_collectPayment_sends_cardRemovedAfterPaymentCapture_event_after_card_removal_and_before_site_capturePayment_completion() { // Given - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) let intent = PaymentIntent.fake() // Success on client-side processing. mockCardReaderService.whenCapturingPayment(thenReturn: Just(intent) @@ -713,7 +609,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { } onProcessingCompletion: { intent in } onCompletion: { result in } - store.onAction(action) + self.cardPresentStore.onAction(action) } // Then @@ -727,10 +623,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// func test_collectPayment_calls_onCompletion_but_not_onProcessingCompletion_after_card_reader_capturePayment_failure() throws { // Given - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) let error = UnderlyingError.readerBusy mockCardReaderService.whenCapturingPayment(thenReturn: Fail(error: error) .eraseToAnyPublisher()) @@ -749,7 +641,7 @@ final class CardPresentPaymentStoreTests: XCTestCase { } onCompletion: { result in promise(result) } - store.onAction(action) + cardPresentStore.onAction(action) } // Then @@ -759,15 +651,11 @@ final class CardPresentPaymentStoreTests: XCTestCase { func test_selectedPaymentGatewayAccount_when_sent_use_before_then_returns_the_same_account() { // Given - let store = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) let account = PaymentGatewayAccount.fake() - store.onAction(CardPresentPaymentAction.use(paymentGatewayAccount: account)) + cardPresentStore.onAction(CardPresentPaymentAction.use(paymentGatewayAccount: account)) let result = waitFor { promise in - store.onAction(CardPresentPaymentAction.selectedPaymentGatewayAccount(onCompletion: { selectedAccount in + self.cardPresentStore.onAction(CardPresentPaymentAction.selectedPaymentGatewayAccount(onCompletion: { selectedAccount in promise(selectedAccount) })) } @@ -777,11 +665,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_checkDeviceSupport_action_passes_configuration_provider_to_service() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let action = CardPresentPaymentAction.checkDeviceSupport(siteID: sampleSiteID, cardReaderType: .appleBuiltIn, discoveryMethod: .localMobile, @@ -793,11 +676,6 @@ final class CardPresentPaymentStoreTests: XCTestCase { } func test_checkDeviceSupport_action_passes_reader_type_and_discovery_method_to_service() { - let cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - cardReaderService: mockCardReaderService) - let action = CardPresentPaymentAction.checkDeviceSupport(siteID: sampleSiteID, cardReaderType: .chipper, discoveryMethod: .bluetoothScan, From 009a740105752b96fa3932b8a23c63d34df5c12c Mon Sep 17 00:00:00 2001 From: Josh Heald Date: Fri, 13 Jan 2023 17:25:14 +0000 Subject: [PATCH 2/2] =?UTF-8?q?8290=20Use=20one=20ReaderConfigProvider=20f?= =?UTF-8?q?or=20the=20app=E2=80=99s=20lifetime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Once the CardReaderConfigProvider is set on the Terminal, it can’t be changed. This means we need to keep the same one around for the lifetime of the app in order to change it when the user logs out and back in again. Failing to do this results in serious errors when using a second account to take IPP transactions. --- .../StripeCardReaderService.swift | 6 +- .../ServiceLocator/ServiceLocator.swift | 14 ++++ .../Classes/Yosemite/AuthenticatedState.swift | 3 +- Yosemite/Yosemite.xcodeproj/project.pbxproj | 8 ++ .../Stores/CardPresentPaymentStore.swift | 75 +---------------- .../Tools/CommonReaderConfigProvider.swift | 82 +++++++++++++++++++ .../MockCommonReaderConfigProviding.swift | 17 ++++ .../Stores/CardPresentPaymentStoreTests.swift | 5 +- 8 files changed, 134 insertions(+), 76 deletions(-) create mode 100644 Yosemite/Yosemite/Tools/CommonReaderConfigProvider.swift create mode 100644 Yosemite/YosemiteTests/Mocks/CardPresentPayments/MockCommonReaderConfigProviding.swift diff --git a/Hardware/Hardware/CardReader/StripeCardReader/StripeCardReaderService.swift b/Hardware/Hardware/CardReader/StripeCardReader/StripeCardReaderService.swift index 9d9d5d5e15b..92f14a3b190 100644 --- a/Hardware/Hardware/CardReader/StripeCardReader/StripeCardReaderService.swift +++ b/Hardware/Hardware/CardReader/StripeCardReader/StripeCardReaderService.swift @@ -861,11 +861,11 @@ private extension StripeCardReaderService { private extension StripeCardReaderService { private func setConfigProvider(_ configProvider: CardReaderConfigProvider) { - readerLocationProvider = configProvider + if !Terminal.hasTokenProvider() { + readerLocationProvider = configProvider - let tokenProvider = DefaultConnectionTokenProvider(provider: configProvider) + let tokenProvider = DefaultConnectionTokenProvider(provider: configProvider) - if !Terminal.hasTokenProvider() { Terminal.setTokenProvider(tokenProvider) } } diff --git a/WooCommerce/Classes/ServiceLocator/ServiceLocator.swift b/WooCommerce/Classes/ServiceLocator/ServiceLocator.swift index b3a802bc736..d4994df100e 100644 --- a/WooCommerce/Classes/ServiceLocator/ServiceLocator.swift +++ b/WooCommerce/Classes/ServiceLocator/ServiceLocator.swift @@ -79,6 +79,8 @@ final class ServiceLocator { private static var _cardReader: CardReaderService = NoOpCardReaderService() #endif + private static var _cardReaderConfigProvider: CommonReaderConfigProviding = CommonReaderConfigProvider() + /// Support for printing receipts /// private static var _receiptPrinter: PrinterService = AirPrintReceiptPrinterService() @@ -207,6 +209,10 @@ final class ServiceLocator { _cardReader } + static var cardReaderConfigProvider: CommonReaderConfigProviding { + _cardReaderConfigProvider + } + /// Provides the access point to the ReceiptPrinterService. /// - Returns: An implementation of the ReceiptPrinterService protocol. static var receiptPrinterService: PrinterService { @@ -336,6 +342,14 @@ extension ServiceLocator { #endif } + static func setCardReaderConfigProvider(_ mock: CommonReaderConfigProviding) { + guard isRunningTests() else { + return + } + + _cardReaderConfigProvider = mock + } + static func setReceiptPrinter(_ mock: PrinterService) { guard isRunningTests() else { return diff --git a/WooCommerce/Classes/Yosemite/AuthenticatedState.swift b/WooCommerce/Classes/Yosemite/AuthenticatedState.swift index 140be197681..2c1b4791937 100644 --- a/WooCommerce/Classes/Yosemite/AuthenticatedState.swift +++ b/WooCommerce/Classes/Yosemite/AuthenticatedState.swift @@ -75,7 +75,8 @@ class AuthenticatedState: StoresManagerState { CardPresentPaymentStore(dispatcher: dispatcher, storageManager: storageManager, network: network, - cardReaderService: ServiceLocator.cardReaderService), + cardReaderService: ServiceLocator.cardReaderService, + cardReaderConfigProvider: ServiceLocator.cardReaderConfigProvider), ReceiptStore(dispatcher: dispatcher, storageManager: storageManager, network: network, diff --git a/Yosemite/Yosemite.xcodeproj/project.pbxproj b/Yosemite/Yosemite.xcodeproj/project.pbxproj index 1df7adf9efd..0997a72c22f 100644 --- a/Yosemite/Yosemite.xcodeproj/project.pbxproj +++ b/Yosemite/Yosemite.xcodeproj/project.pbxproj @@ -108,6 +108,8 @@ 02FF056B23DED3670058E6E7 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 02FF056A23DED3670058E6E7 /* Media.xcassets */; }; 02FF056D23DEDCB90058E6E7 /* MockImageSourceWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02FF056C23DEDCB90058E6E7 /* MockImageSourceWriter.swift */; }; 02FF056F23E04F320058E6E7 /* MockMediaExportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02FF056E23E04F320058E6E7 /* MockMediaExportService.swift */; }; + 030C94A62971C73700F7F65D /* MockCommonReaderConfigProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030C94A52971C73700F7F65D /* MockCommonReaderConfigProviding.swift */; }; + 030C94A82971C96F00F7F65D /* CommonReaderConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030C94A72971C96F00F7F65D /* CommonReaderConfigProvider.swift */; }; 031C1EAA27B1702800298699 /* WCPayCharge+ReadOnlyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031C1EA927B1702800298699 /* WCPayCharge+ReadOnlyConvertible.swift */; }; 031C1EAC27B1873200298699 /* WCPayCardPresentReceiptDetails+ReadOnlyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031C1EAB27B1873200298699 /* WCPayCardPresentReceiptDetails+ReadOnlyConvertible.swift */; }; 031C1EAE27B1877000298699 /* WCPayCardPresentPaymentDetails+ReadOnlyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031C1EAD27B1877000298699 /* WCPayCardPresentPaymentDetails+ReadOnlyConvertible.swift */; }; @@ -541,6 +543,8 @@ 02FF056A23DED3670058E6E7 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = ""; }; 02FF056C23DEDCB90058E6E7 /* MockImageSourceWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockImageSourceWriter.swift; sourceTree = ""; }; 02FF056E23E04F320058E6E7 /* MockMediaExportService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaExportService.swift; sourceTree = ""; }; + 030C94A52971C73700F7F65D /* MockCommonReaderConfigProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCommonReaderConfigProviding.swift; sourceTree = ""; }; + 030C94A72971C96F00F7F65D /* CommonReaderConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonReaderConfigProvider.swift; sourceTree = ""; }; 031C1EA927B1702800298699 /* WCPayCharge+ReadOnlyConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WCPayCharge+ReadOnlyConvertible.swift"; sourceTree = ""; }; 031C1EAB27B1873200298699 /* WCPayCardPresentReceiptDetails+ReadOnlyConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WCPayCardPresentReceiptDetails+ReadOnlyConvertible.swift"; sourceTree = ""; }; 031C1EAD27B1877000298699 /* WCPayCardPresentPaymentDetails+ReadOnlyConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WCPayCardPresentPaymentDetails+ReadOnlyConvertible.swift"; sourceTree = ""; }; @@ -1382,6 +1386,7 @@ B56C1EC120EAE2E500D749F9 /* ReadOnlyConvertible.swift */, B52E002D211A3F5500700FDE /* ReadOnlyType.swift */, 0271E1652509CF0100633F7A /* AnyError.swift */, + 030C94A72971C96F00F7F65D /* CommonReaderConfigProvider.swift */, ); path = Tools; sourceTree = ""; @@ -1727,6 +1732,7 @@ isa = PBXGroup; children = ( D88303EF25E45E6F00C877F9 /* MockCardReaderService.swift */, + 030C94A52971C73700F7F65D /* MockCommonReaderConfigProviding.swift */, D87F27DA25E7E8EA006EC8C9 /* MockCardReader.swift */, D8652E4726307A5000350F37 /* MockReceiptPrinterService.swift */, ); @@ -2057,6 +2063,7 @@ 02124DAE2431C11600980D74 /* Media+ProductImage.swift in Sources */, DEFD6D9526443CA100E51E0D /* SitePluginStore.swift in Sources */, 26577517243D5E42003168A5 /* ProductCategoryUpdated.swift in Sources */, + 030C94A82971C96F00F7F65D /* CommonReaderConfigProvider.swift in Sources */, 261CF1F1255B389F0090D8D3 /* PaymentGatewayStore.swift in Sources */, E18FDAFE28F97EB9008519BA /* AppAccountToken.swift in Sources */, 02FF055023D983F30058E6E7 /* ExportableAsset.swift in Sources */, @@ -2300,6 +2307,7 @@ B9AECD482851F28E00E78584 /* Order+CardPresentPaymentTests.swift in Sources */, 02124DB02431C18700980D74 /* Media+ProductImageTests.swift in Sources */, 0248B3672459020500A271A4 /* ResultsController+FilterProductTests.swift in Sources */, + 030C94A62971C73700F7F65D /* MockCommonReaderConfigProviding.swift in Sources */, B54EAF2121188C470029C35E /* EntityListenerTests.swift in Sources */, 02FF056F23E04F320058E6E7 /* MockMediaExportService.swift in Sources */, DE6831DD26445B2B00E88B9E /* SitePluginStoreTests.swift in Sources */, diff --git a/Yosemite/Yosemite/Stores/CardPresentPaymentStore.swift b/Yosemite/Yosemite/Stores/CardPresentPaymentStore.swift index 2fbda6f8f31..0dd61fa74e3 100644 --- a/Yosemite/Yosemite/Stores/CardPresentPaymentStore.swift +++ b/Yosemite/Yosemite/Stores/CardPresentPaymentStore.swift @@ -15,7 +15,7 @@ public final class CardPresentPaymentStore: Store { /// Card reader config provider /// - private let commonReaderConfigProvider: CommonReaderConfigProvider + private let commonReaderConfigProvider: CommonReaderConfigProviding private var paymentGatewayAccount: PaymentGatewayAccount? { didSet { @@ -51,10 +51,11 @@ public final class CardPresentPaymentStore: Store { dispatcher: Dispatcher, storageManager: StorageManagerType, network: Network, - cardReaderService: CardReaderService + cardReaderService: CardReaderService, + cardReaderConfigProvider: CommonReaderConfigProviding ) { self.cardReaderService = cardReaderService - self.commonReaderConfigProvider = CommonReaderConfigProvider() + self.commonReaderConfigProvider = cardReaderConfigProvider self.remote = WCPayRemote(network: network) self.stripeRemote = StripeRemote(network: network) super.init(dispatcher: dispatcher, storageManager: storageManager, network: network) @@ -370,74 +371,6 @@ private extension CardPresentPaymentStore { onCompletion(publisher) } } -private extension CardPresentPaymentStore { - final class CommonReaderConfigProvider: CardReaderConfigProvider { - var siteID: Int64? - var readerConfigRemote: CardReaderCapableRemote? - - public func setContext(siteID: Int64, remote: CardReaderCapableRemote) { - self.siteID = siteID - self.readerConfigRemote = remote - } - - public func fetchToken(completion: @escaping(Result) -> Void) { - guard let siteID = self.siteID else { - return - } - - readerConfigRemote?.loadConnectionToken(for: siteID) { result in - switch result { - case .success(let token): - completion(.success(token.token)) - case .failure(let error): - if let configError = CardReaderConfigError(error: error) { - completion(.failure(configError)) - } else { - completion(.failure(error)) - } - } - } - } - - public func fetchDefaultLocationID(completion: @escaping(Result) -> Void) { - guard let siteID = self.siteID else { - return - } - - readerConfigRemote?.loadDefaultReaderLocation(for: siteID) { result in - switch result { - case .success(let location): - let readerLocation = location.toReaderLocation(siteID: siteID) - completion(.success(readerLocation.id)) - case .failure(let error): - if let configError = CardReaderConfigError(error: error) { - completion(.failure(configError)) - } else { - completion(.failure(error)) - } - } - } - } - } -} - -private extension CardReaderConfigError { - init?(error: Error) { - guard let dotcomError = error as? DotcomError else { - return nil - } - switch dotcomError { - case .unknown("store_address_is_incomplete", let message): - self = .incompleteStoreAddress(adminUrl: URL(string: message ?? "")) - return - case .unknown("postal_code_invalid", _): - self = .invalidPostalCode - return - default: - return nil - } - } -} // MARK: Networking Methods private extension CardPresentPaymentStore { diff --git a/Yosemite/Yosemite/Tools/CommonReaderConfigProvider.swift b/Yosemite/Yosemite/Tools/CommonReaderConfigProvider.swift new file mode 100644 index 00000000000..5581c1f6398 --- /dev/null +++ b/Yosemite/Yosemite/Tools/CommonReaderConfigProvider.swift @@ -0,0 +1,82 @@ +import Foundation +import Hardware +import Networking + +public protocol CardReaderRemoteConfigLoading { + func setContext(siteID: Int64, remote: CardReaderCapableRemote) +} + +public protocol CommonReaderConfigProviding: CardReaderRemoteConfigLoading & CardReaderConfigProvider {} + + +final public class CommonReaderConfigProvider: CommonReaderConfigProviding { + var siteID: Int64? + var readerConfigRemote: CardReaderCapableRemote? + + public init(siteID: Int64? = nil, readerConfigRemote: CardReaderCapableRemote? = nil) { + self.siteID = siteID + self.readerConfigRemote = readerConfigRemote + } + + public func setContext(siteID: Int64, remote: CardReaderCapableRemote) { + self.siteID = siteID + self.readerConfigRemote = remote + } + + public func fetchToken(completion: @escaping(Result) -> Void) { + guard let siteID = self.siteID else { + return + } + + readerConfigRemote?.loadConnectionToken(for: siteID) { result in + switch result { + case .success(let token): + completion(.success(token.token)) + case .failure(let error): + if let configError = CardReaderConfigError(error: error) { + completion(.failure(configError)) + } else { + completion(.failure(error)) + } + } + } + } + + public func fetchDefaultLocationID(completion: @escaping(Result) -> Void) { + guard let siteID = self.siteID else { + return + } + + readerConfigRemote?.loadDefaultReaderLocation(for: siteID) { result in + switch result { + case .success(let location): + let readerLocation = location.toReaderLocation(siteID: siteID) + completion(.success(readerLocation.id)) + case .failure(let error): + if let configError = CardReaderConfigError(error: error) { + completion(.failure(configError)) + } else { + completion(.failure(error)) + } + } + } + } +} + +private extension CardReaderConfigError { + init?(error: Error) { + guard let dotcomError = error as? DotcomError else { + return nil + } + switch dotcomError { + case .unknown("store_address_is_incomplete", let message): + self = .incompleteStoreAddress(adminUrl: URL(string: message ?? "")) + return + case .unknown("postal_code_invalid", _): + self = .invalidPostalCode + return + default: + return nil + } + } +} diff --git a/Yosemite/YosemiteTests/Mocks/CardPresentPayments/MockCommonReaderConfigProviding.swift b/Yosemite/YosemiteTests/Mocks/CardPresentPayments/MockCommonReaderConfigProviding.swift new file mode 100644 index 00000000000..32c04e5a2e9 --- /dev/null +++ b/Yosemite/YosemiteTests/Mocks/CardPresentPayments/MockCommonReaderConfigProviding.swift @@ -0,0 +1,17 @@ +import Foundation + +@testable import Yosemite + +final class MockCommonReaderConfigProviding: CommonReaderConfigProviding { + func fetchToken(completion: @escaping (Result) -> Void) { + completion(.success("mock_token")) + } + + func fetchDefaultLocationID(completion: @escaping (Result) -> Void) { + completion(.success("mock_location")) + } + + func setContext(siteID: Int64, remote: Yosemite.CardReaderCapableRemote) { + // no-op + } +} diff --git a/Yosemite/YosemiteTests/Stores/CardPresentPaymentStoreTests.swift b/Yosemite/YosemiteTests/Stores/CardPresentPaymentStoreTests.swift index dc3a209659c..0e1455ea3fb 100644 --- a/Yosemite/YosemiteTests/Stores/CardPresentPaymentStoreTests.swift +++ b/Yosemite/YosemiteTests/Stores/CardPresentPaymentStoreTests.swift @@ -32,6 +32,8 @@ final class CardPresentPaymentStoreTests: XCTestCase { /// Mock Card Reader Service: In memory private var mockCardReaderService: MockCardReaderService! + private var mockCardReaderConfigProvider: CommonReaderConfigProviding! + private var cardPresentStore: CardPresentPaymentStore! /// Dummy Site ID @@ -72,7 +74,8 @@ final class CardPresentPaymentStoreTests: XCTestCase { cardPresentStore = CardPresentPaymentStore(dispatcher: dispatcher, storageManager: storageManager, network: network, - cardReaderService: mockCardReaderService) + cardReaderService: mockCardReaderService, + cardReaderConfigProvider: mockCardReaderConfigProvider) } override func tearDown() {