diff --git a/Gemfile b/Gemfile index 4b40ce94f86..f0625a89df9 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,7 @@ end gem 'danger-dangermattic', '~> 1.2' gem 'dotenv' # 2.217.0 includes a fix for Xcode 15 test results parsing in CI -gem 'fastlane', '~> 2.217' +gem 'fastlane', '~> 2.228' gem 'fastlane-plugin-firebase_app_distribution', '~> 0.10' gem 'fastlane-plugin-sentry', '~> 1.0' # This comment avoids typing to switch to a development version for testing. diff --git a/Gemfile.lock b/Gemfile.lock index befe6479747..b3e005ed3d9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -23,24 +23,27 @@ GEM artifactory (3.0.17) ast (2.4.2) atomos (0.1.3) - aws-eventstream (1.3.0) - aws-partitions (1.1029.0) - aws-sdk-core (3.214.1) + aws-eventstream (1.4.0) + aws-partitions (1.1154.0) + aws-sdk-core (3.232.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) + base64 + bigdecimal jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.96.0) - aws-sdk-core (~> 3, >= 3.210.0) + logger + aws-sdk-kms (1.112.0) + aws-sdk-core (~> 3, >= 3.231.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.176.1) - aws-sdk-core (~> 3, >= 3.210.0) + aws-sdk-s3 (1.198.0) + aws-sdk-core (~> 3, >= 3.231.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) - aws-sigv4 (1.10.1) + aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) - base64 (0.2.0) + base64 (0.3.0) benchmark (0.4.1) bigdecimal (3.2.2) buildkit (1.6.1) @@ -85,7 +88,7 @@ GEM rubocop (~> 1.0) declarative (0.0.20) diffy (3.4.4) - digest-crc (0.6.5) + digest-crc (0.7.0) rake (>= 12.0.0, < 14.0.0) domain_name (0.6.20240107) dotenv (2.8.1) @@ -108,12 +111,12 @@ GEM faraday (>= 0.8.0) http-cookie (~> 1.0.0) faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) + faraday-em_synchrony (1.0.1) faraday-excon (1.1.0) faraday-http-cache (2.5.1) faraday (>= 0.8) faraday-httpclient (1.0.1) - faraday-multipart (1.1.0) + faraday-multipart (1.1.1) multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) @@ -122,8 +125,8 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.1) faraday (~> 1.0) - fastimage (2.3.1) - fastlane (2.226.0) + fastimage (2.4.0) + fastlane (2.228.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -163,7 +166,7 @@ GEM tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.4.0) + xcpretty (~> 0.4.1) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) fastlane-plugin-firebase_app_distribution (0.10.0) google-apis-firebaseappdistribution_v1 (~> 0.3.0) @@ -213,12 +216,12 @@ GEM google-apis-core (>= 0.11.0, < 2.a) google-apis-storage_v1 (0.31.0) google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.7.1) + google-cloud-core (1.8.0) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.4.0) + google-cloud-errors (1.5.0) google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) @@ -236,13 +239,14 @@ GEM highline (2.0.3) http-cookie (1.0.8) domain_name (~> 0.5) - httpclient (2.8.3) + httpclient (2.9.0) + mutex_m i18n (1.14.7) concurrent-ruby (~> 1.0) java-properties (0.3.0) jmespath (1.6.2) - json (2.9.1) - jwt (2.10.1) + json (2.13.2) + jwt (2.10.2) base64 kramdown (2.5.1) rexml (>= 3.3.9) @@ -254,11 +258,12 @@ GEM mini_mime (1.1.5) mini_portile2 (2.8.9) minitest (5.25.5) - multi_json (1.15.0) + multi_json (1.17.0) multipart-post (2.4.1) + mutex_m (0.3.0) nanaimo (0.4.0) nap (1.1.0) - naturally (2.2.1) + naturally (2.3.0) nkf (0.2.0) nokogiri (1.18.8) mini_portile2 (~> 2.8.2) @@ -281,7 +286,7 @@ GEM highline (>= 1.6) options (~> 2.3.0) pstore (0.1.3) - public_suffix (4.0.7) + public_suffix (6.0.2) racc (1.8.1) rainbow (3.1.1) rake (12.3.3) @@ -294,7 +299,7 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.4.0) + rexml (3.4.2) rmagick (4.3.0) rouge (3.28.0) rubocop (1.68.0) @@ -313,16 +318,16 @@ GEM rubocop (~> 1.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) - rubyzip (2.3.2) + rubyzip (2.4.1) sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) securerandom (0.4.1) security (0.1.5) - signet (0.19.0) + signet (0.21.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) - jwt (>= 1.5, < 3.0) + jwt (>= 1.5, < 4.0) multi_json (~> 1.10) simctl (1.6.10) CFPropertyList @@ -352,7 +357,7 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) - xcpretty (0.4.0) + xcpretty (0.4.1) rouge (~> 3.28.0) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) @@ -366,7 +371,7 @@ PLATFORMS DEPENDENCIES danger-dangermattic (~> 1.2) dotenv - fastlane (~> 2.217) + fastlane (~> 2.228) fastlane-plugin-firebase_app_distribution (~> 0.10) fastlane-plugin-sentry (~> 1.0) fastlane-plugin-wpmreleasetoolkit (~> 13.3, >= 13.3.1) diff --git a/WooCommerce/WooCommerceTests/POS/Controllers/PointOfSaleOrderControllerTests.swift b/WooCommerce/WooCommerceTests/POS/Controllers/PointOfSaleOrderControllerTests.swift index bfb76d337d0..8be5311ce21 100644 --- a/WooCommerce/WooCommerceTests/POS/Controllers/PointOfSaleOrderControllerTests.swift +++ b/WooCommerce/WooCommerceTests/POS/Controllers/PointOfSaleOrderControllerTests.swift @@ -182,8 +182,11 @@ struct PointOfSaleOrderControllerTests { @Test func sendReceipt_when_there_is_no_order_then_will_not_trigger() async throws { // Given + let mockFeatureFlagService = MockFeatureFlagService() + mockFeatureFlagService.isFeatureFlagEnabledReturnValue[.pointOfSaleReceipts] = true let sut = PointOfSaleOrderController(orderService: mockOrderService, - receiptService: mockReceiptService) + receiptService: mockReceiptService, + featureFlagService: mockFeatureFlagService) let email = "test@example.com" // When @@ -199,8 +202,11 @@ struct PointOfSaleOrderControllerTests { @Test func sendReceipt_calls_both_updateOrder_and_sendReceipt() async throws { // Given + let mockFeatureFlagService = MockFeatureFlagService() + mockFeatureFlagService.isFeatureFlagEnabledReturnValue[.pointOfSaleReceipts] = true let sut = PointOfSaleOrderController(orderService: mockOrderService, - receiptService: mockReceiptService) + receiptService: mockReceiptService, + featureFlagService: mockFeatureFlagService) let order = Order.fake() let recipientEmail = "test@fake.com" mockOrderService.orderToReturn = order @@ -220,7 +226,8 @@ struct PointOfSaleOrderControllerTests { do { // Given/When let sut = PointOfSaleOrderController(orderService: mockOrderService, - receiptService: mockReceiptService) + receiptService: mockReceiptService, + celebration: MockPaymentCaptureCelebration()) try await sut.collectCashPayment(changeDueAmount: nil) } catch let error as PointOfSaleOrderController.PointOfSaleOrderControllerError { // Then @@ -253,7 +260,8 @@ struct PointOfSaleOrderControllerTests { @Test func collectCashPayment_passes_changeDueAmount_to_order_service() async throws { // Given let sut = PointOfSaleOrderController(orderService: mockOrderService, - receiptService: mockReceiptService) + receiptService: mockReceiptService, + celebration: MockPaymentCaptureCelebration()) let orderItem = OrderItem.fake() let fakeOrder = Order.fake().copy(items: [orderItem]) @@ -600,7 +608,8 @@ struct PointOfSaleOrderControllerTests { let sut = PointOfSaleOrderController(orderService: orderService, receiptService: MockReceiptService(), - analytics: mockAnalytics) + analytics: mockAnalytics, + celebration: MockPaymentCaptureCelebration()) // In order to test the order controller failure we need to succeed first in creating a successful order: let orderItem = OrderItem.fake() @@ -629,15 +638,21 @@ struct PointOfSaleOrderControllerTests { version: "10.0.0-dev", active: true)) + let mockFeatureFlagService = MockFeatureFlagService() + mockFeatureFlagService.isFeatureFlagEnabledReturnValue[.pointOfSaleReceipts] = true + let sut = PointOfSaleOrderController(orderService: orderService, receiptService: receiptService, analytics: analytics, + featureFlagService: mockFeatureFlagService, pluginsService: mockPluginsService) let order = Order.fake() orderService.orderToReturn = order // We need an existing order before we can send a receipt await sut.syncOrder(for: .init(purchasableItems: [makeItem()]), retryHandler: { }) + analyticsProvider.receivedEvents.removeAll() + analyticsProvider.receivedProperties.removeAll() // When try await sut.sendReceipt(recipientEmail: "test@example.com") @@ -649,9 +664,12 @@ struct PointOfSaleOrderControllerTests { @Test func sendReceipt_without_order_tracks_failure_without_eligible_for_pos_receipt() async throws { // Given + let mockFeatureFlagService = MockFeatureFlagService() + mockFeatureFlagService.isFeatureFlagEnabledReturnValue[.pointOfSaleReceipts] = true let sut = PointOfSaleOrderController(orderService: orderService, receiptService: receiptService, - analytics: analytics) + analytics: analytics, + featureFlagService: mockFeatureFlagService) // When do { @@ -671,9 +689,12 @@ struct PointOfSaleOrderControllerTests { version: "10.0.0-dev", active: true)) + let mockFeatureFlagService = MockFeatureFlagService() + mockFeatureFlagService.isFeatureFlagEnabledReturnValue[.pointOfSaleReceipts] = true let sut = PointOfSaleOrderController(orderService: orderService, receiptService: receiptService, analytics: analytics, + featureFlagService: mockFeatureFlagService, pluginsService: mockPluginsService) receiptService.sendReceiptResult = .failure(DotcomError.unknown(code: "test_error", message: "Test error")) @@ -683,6 +704,8 @@ struct PointOfSaleOrderControllerTests { // We need an existing order before we can send a receipt await sut.syncOrder(for: .init(purchasableItems: [makeItem()]), retryHandler: { }) + analyticsProvider.receivedEvents.removeAll() + analyticsProvider.receivedProperties.removeAll() // When do { diff --git a/WooCommerce/WooCommerceTests/POS/Mocks/MockPOSCollectOrderPaymentAnalyticsTracker.swift b/WooCommerce/WooCommerceTests/POS/Mocks/MockPOSCollectOrderPaymentAnalyticsTracker.swift index c1a14eef099..b60cb69b2a1 100644 --- a/WooCommerce/WooCommerceTests/POS/Mocks/MockPOSCollectOrderPaymentAnalyticsTracker.swift +++ b/WooCommerce/WooCommerceTests/POS/Mocks/MockPOSCollectOrderPaymentAnalyticsTracker.swift @@ -28,8 +28,9 @@ final class MockPOSCollectOrderPaymentAnalyticsTracker: POSCollectOrderPaymentAn // no-op } + var didCallTrackSuccessfulCashPayment = false func trackSuccessfulCashPayment() { - // no-op + didCallTrackSuccessfulCashPayment = true } var connectedReaderModel: String? diff --git a/WooCommerce/WooCommerceTests/POS/Models/PointOfSaleAggregateModelTests.swift b/WooCommerce/WooCommerceTests/POS/Models/PointOfSaleAggregateModelTests.swift index ec9f4bbbbb7..2410f5529ae 100644 --- a/WooCommerce/WooCommerceTests/POS/Models/PointOfSaleAggregateModelTests.swift +++ b/WooCommerce/WooCommerceTests/POS/Models/PointOfSaleAggregateModelTests.swift @@ -906,7 +906,20 @@ struct PointOfSaleAggregateModelTests { await sut.startCashPayment() // Then - #expect(mockAnalyticsProvider.receivedEvents.first(where: { $0 == "cash_payment_tapped" }) != nil) + #expect(mockAnalyticsProvider.receivedEvents.first(where: { $0 == "checkout_cash_payment_tapped" }) != nil) + } + + @Test func collectCashPayment_when_invoked_tracks_expected_event() async throws { + // Given + let analyticsTracker = MockPOSCollectOrderPaymentAnalyticsTracker() + let sut = makePointOfSaleAggregateModel(orderController: orderController, + collectOrderPaymentAnalyticsTracker: analyticsTracker) + + // When + try await sut.collectCashPayment(changeDueAmount: "0.00") + + // Then + #expect(analyticsTracker.didCallTrackSuccessfulCashPayment == true) } }