diff --git a/WooCommerce/Classes/ViewModels/CardPresentPayments/ReceiptActionCoordinator.swift b/WooCommerce/Classes/ViewModels/CardPresentPayments/ReceiptActionCoordinator.swift index 9e12087fbce..36c561af5ec 100644 --- a/WooCommerce/Classes/ViewModels/CardPresentPayments/ReceiptActionCoordinator.swift +++ b/WooCommerce/Classes/ViewModels/CardPresentPayments/ReceiptActionCoordinator.swift @@ -7,21 +7,27 @@ struct ReceiptActionCoordinator { countryCode: String, cardReaderModel: String?, stores: StoresManager, - analytics: Analytics) { + analytics: Analytics) async { analytics.track(event: .InPersonPayments.receiptPrintTapped(countryCode: countryCode, cardReaderModel: cardReaderModel)) - let action = ReceiptAction.print(order: order, parameters: params) { (result) in - switch result { - case .success: - analytics.track(event: .InPersonPayments.receiptPrintSuccess(countryCode: countryCode, cardReaderModel: cardReaderModel)) - case .cancel: - analytics.track(event: .InPersonPayments.receiptPrintCanceled(countryCode: countryCode, cardReaderModel: cardReaderModel)) - case .failure(let error): - analytics.track(event: .InPersonPayments.receiptPrintFailed(error: error, countryCode: countryCode, cardReaderModel: cardReaderModel)) - DDLogError("⛔️ Failed to print receipt: \(error.localizedDescription)") + await withCheckedContinuation { continuation in + let action = ReceiptAction.print(order: order, parameters: params) { (result) in + switch result { + case .success: + analytics.track(event: .InPersonPayments.receiptPrintSuccess(countryCode: countryCode, cardReaderModel: cardReaderModel)) + case .cancel: + analytics.track(event: .InPersonPayments.receiptPrintCanceled(countryCode: countryCode, cardReaderModel: cardReaderModel)) + case .failure(let error): + analytics.track(event: .InPersonPayments.receiptPrintFailed(error: error, countryCode: countryCode, cardReaderModel: cardReaderModel)) + DDLogError("⛔️ Failed to print receipt: \(error.localizedDescription)") + } + + continuation.resume() } - } - stores.dispatch(action) + Task { @MainActor in + stores.dispatch(action) + } + } } } diff --git a/WooCommerce/Classes/ViewModels/CardPresentPayments/ReceiptViewModel.swift b/WooCommerce/Classes/ViewModels/CardPresentPayments/ReceiptViewModel.swift index 55fe3e2a38b..33743855801 100644 --- a/WooCommerce/Classes/ViewModels/CardPresentPayments/ReceiptViewModel.swift +++ b/WooCommerce/Classes/ViewModels/CardPresentPayments/ReceiptViewModel.swift @@ -48,12 +48,14 @@ final class ReceiptViewModel { /// Prints the receipt func printReceipt() { - ReceiptActionCoordinator.printReceipt(for: order, - params: receipt, - countryCode: countryCode, - cardReaderModel: nil, - stores: stores, - analytics: ServiceLocator.analytics) + Task { @MainActor in + await ReceiptActionCoordinator.printReceipt(for: order, + params: receipt, + countryCode: countryCode, + cardReaderModel: nil, + stores: stores, + analytics: ServiceLocator.analytics) + } } /// Returns a boolean that indicates whether email is supported for the app and device so that email UI is only displayed when it is supported. diff --git a/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/CollectOrderPaymentUseCase.swift b/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/CollectOrderPaymentUseCase.swift index 07cfed544cb..28574e7332c 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/CollectOrderPaymentUseCase.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/CollectOrderPaymentUseCase.swift @@ -442,17 +442,18 @@ private extension CollectOrderPaymentUseCase { alertsPresenter.present(viewModel: paymentAlerts.success(printReceipt: { [order, configuration, weak self] in guard let self = self else { return } - // Inform about flow completion. - onCompleted() - // Delegate print action - ReceiptActionCoordinator.printReceipt(for: order, - params: receiptParameters, - countryCode: configuration.countryCode, - cardReaderModel: self.connectedReader?.readerType.model, - stores: self.stores, - analytics: self.analytics) - + Task { @MainActor in + await ReceiptActionCoordinator.printReceipt(for: order, + params: receiptParameters, + countryCode: configuration.countryCode, + cardReaderModel: self.connectedReader?.readerType.model, + stores: self.stores, + analytics: self.analytics) + + // Inform about flow completion. + onCompleted() + } }, emailReceipt: { [order, analytics, paymentOrchestrator, configuration, weak self] in guard let self = self else { return } diff --git a/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/LegacyCollectOrderPaymentUseCase.swift b/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/LegacyCollectOrderPaymentUseCase.swift index 850a70436f0..6a53d10791d 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/LegacyCollectOrderPaymentUseCase.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/LegacyCollectOrderPaymentUseCase.swift @@ -400,17 +400,17 @@ private extension LegacyCollectOrderPaymentUseCase { alerts.success(printReceipt: { [order, configuration, weak self] in guard let self = self else { return } - // Inform about flow completion. - onCompleted() - // Delegate print action - ReceiptActionCoordinator.printReceipt(for: order, - params: receiptParameters, - countryCode: configuration.countryCode, - cardReaderModel: self.connectedReader?.readerType.model, - stores: self.stores, - analytics: self.analytics) - + Task { @MainActor in + await ReceiptActionCoordinator.printReceipt(for: order, + params: receiptParameters, + countryCode: configuration.countryCode, + cardReaderModel: self.connectedReader?.readerType.model, + stores: self.stores, + analytics: self.analytics) + // Inform about flow completion. + onCompleted() + } }, emailReceipt: { [order, analytics, paymentOrchestrator, configuration, weak self] in guard let self = self else { return } diff --git a/WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/LegacyCollectOrderPaymentUseCaseTests.swift b/WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/LegacyCollectOrderPaymentUseCaseTests.swift index e88ad57ef76..0a3e15c1b98 100644 --- a/WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/LegacyCollectOrderPaymentUseCaseTests.swift +++ b/WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/LegacyCollectOrderPaymentUseCaseTests.swift @@ -110,27 +110,6 @@ final class LegacyCollectOrderPaymentUseCaseTests: XCTestCase { } // MARK: Success alert actions - - func test_printing_receipt_from_collectPayment_success_alert_tracks_receiptPrintTapped_event() throws { - // Given - let intent = PaymentIntent.fake().copy(charges: [.fake().copy(paymentMethod: .cardPresent(details: .fake()))]) - mockSuccessfulCardPresentPaymentActions(intent: intent) - - // When - waitFor { promise in - self.useCase.collectPayment(onCollect: { _ in - promise(()) - }, onCancel: {}, onCompleted: {}) - } - alerts.printReceiptFromSuccessAlert?() - - // Then - let indexOfEvent = try XCTUnwrap(analyticsProvider.receivedEvents.firstIndex(where: { $0 == "receipt_print_tapped"})) - let eventProperties = try XCTUnwrap(analyticsProvider.receivedProperties[indexOfEvent]) - XCTAssertEqual(eventProperties["card_reader_model"] as? String, Mocks.cardReaderModel) - XCTAssertEqual(eventProperties["country"] as? String, "US") - } - func test_emailing_receipt_from_collectPayment_success_alert_tracks_receiptEmailTapped_event() throws { // Given let intent = PaymentIntent.fake().copy(charges: [.fake().copy(paymentMethod: .cardPresent(details: .fake()))]) diff --git a/WooCommerce/WooCommerceTests/ViewRelated/CardPresentPayments/ReceiptActionCoordinatorTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/CardPresentPayments/ReceiptActionCoordinatorTests.swift index 896b5d2aefa..ac770b8a71a 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/CardPresentPayments/ReceiptActionCoordinatorTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/CardPresentPayments/ReceiptActionCoordinatorTests.swift @@ -6,18 +6,39 @@ import Hardware @testable import WooCommerce final class ReceiptActionCoordinatorTests: XCTestCase { - func test_printReceipt_logs_receiptPrintTapped_analyticEvent() throws { + private var storesManager: MockStoresManager! + + override func setUp() { + super.setUp() + + storesManager = MockStoresManager(sessionManager: .makeForTesting(authenticated: true)) + } + + override func tearDown() { + storesManager = nil + } + + func test_printReceipt_logs_receiptPrintTapped_analyticEvent() async throws { // Given let analytics = MockAnalyticsProvider() let order = MockOrders().makeOrder() let params = CardPresentReceiptParameters.makeParams() + storesManager.whenReceivingAction(ofType: ReceiptAction.self) { action in + switch action { + case let .print(_, _, completion): + completion(.success) + default: + break + } + } + // When - ReceiptActionCoordinator.printReceipt(for: order, + await ReceiptActionCoordinator.printReceipt(for: order, params: params, countryCode: "CA", cardReaderModel: "WISEPAD_3", - stores: ServiceLocator.stores, + stores: storesManager, analytics: WooAnalytics(analyticsProvider: analytics)) // Then @@ -27,18 +48,26 @@ final class ReceiptActionCoordinatorTests: XCTestCase { XCTAssertEqual(eventProperties["country"] as? String, "CA") } - func test_printReceipt_sends_print_receiptAction() throws { + func test_printReceipt_sends_print_receiptAction() async throws { // Given let order = MockOrders().makeOrder() let params = CardPresentReceiptParameters.makeParams() - let storesManager = MockStoresManager(sessionManager: .makeForTesting(authenticated: true)) storesManager.reset() assertEmpty(storesManager.receivedActions) + storesManager.whenReceivingAction(ofType: ReceiptAction.self) { action in + switch action { + case let .print(_, _, completion): + completion(.success) + default: + break + } + } + // When - ReceiptActionCoordinator.printReceipt(for: order, + await ReceiptActionCoordinator.printReceipt(for: order, params: params, countryCode: "CA", cardReaderModel: nil, @@ -57,48 +86,53 @@ final class ReceiptActionCoordinatorTests: XCTestCase { } } - func test_printReceipt_success_logs_receiptPrintSuccess_analyticEvent() throws { - try assertAnalyticLogged(.receiptPrintSuccess, for: .success) + func test_printReceipt_success_logs_receiptPrintSuccess_analyticEvent() async throws { + try await assertAnalyticLogged(.receiptPrintSuccess, for: .success) } - func test_printReceipt_cancel_logs_receiptPrintCanceled_analyticEvent() throws { - try assertAnalyticLogged(.receiptPrintCanceled, for: .cancel) + func test_printReceipt_cancel_logs_receiptPrintCanceled_analyticEvent() async throws { + try await assertAnalyticLogged(.receiptPrintCanceled, for: .cancel) } - func test_printReceipt_fail_logs_receiptPrintFailed_analyticEvent() throws { + func test_printReceipt_fail_logs_receiptPrintFailed_analyticEvent() async throws { let error = NSError(domain: "errordomain", code: 123, userInfo: nil) - try assertAnalyticLogged(.receiptPrintFailed, for: .failure(error)) + try await assertAnalyticLogged(.receiptPrintFailed, for: .failure(error)) } } extension ReceiptActionCoordinatorTests { - func assertAnalyticLogged(_ analytic: WooAnalyticsStat, for printingResult: PrintingResult) throws { + func assertAnalyticLogged(_ analytic: WooAnalyticsStat, for printingResult: PrintingResult) async throws { // Given let order = MockOrders().makeOrder() let params = CardPresentReceiptParameters.makeParams() + let countryCode = "CA" + let cardReaderModel = "test_reader" + - let storesManager = MockStoresManager(sessionManager: .makeForTesting(authenticated: true)) let analytics = MockAnalyticsProvider() + storesManager.whenReceivingAction(ofType: ReceiptAction.self) { action in + switch action { + case let .print(_, _, completion): + completion(printingResult) + default: + break + } + } + // When - ReceiptActionCoordinator.printReceipt(for: order, + await ReceiptActionCoordinator.printReceipt(for: order, params: params, countryCode: "CA", - cardReaderModel: nil, + cardReaderModel: cardReaderModel, stores: storesManager, analytics: WooAnalytics(analyticsProvider: analytics)) - //Then - let action = try XCTUnwrap(storesManager.receivedActions.first as? ReceiptAction) - switch action { - case .print(order: _, parameters: _, let completion): - completion(printingResult) - - let receivedEvents = analytics.receivedEvents - XCTAssert(receivedEvents.contains(analytic.rawValue)) - default: - XCTFail("Print Receipt failed to dispatch .print action") - } + // Then + let indexOfEvent = try XCTUnwrap(analytics.receivedEvents.firstIndex(where: { $0 == analytic.rawValue})) + let eventProperties = try XCTUnwrap(analytics.receivedProperties[indexOfEvent]) + XCTAssertEqual(eventProperties["card_reader_model"] as? String, cardReaderModel) + XCTAssertEqual(eventProperties["country"] as? String, countryCode) } }