From bfb4d116c7b564c22f9cc1ca5e8069eed3d3d524 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Wed, 4 Dec 2024 12:58:07 +0530 Subject: [PATCH 1/9] Track favorite product filter in analytics event. --- .../FavoriteProductsUseCase.swift | 2 ++ .../Filters/FilterProductListViewModel.swift | 6 +++++- .../FilterProductListViewModelTests.swift | 17 ++++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift b/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift index 1ee45517fac..5af3707e3af 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift @@ -18,6 +18,8 @@ struct FavoriteProductsFilter: Equatable, FilterType { let description = Localization.favoriteProducts let isActive = true + + let analyticsDescription = "favorite_products" } private extension FavoriteProductsFilter { diff --git a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift index add718716bc..c4abc3c329a 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift @@ -43,7 +43,11 @@ final class FilterProductListViewModel: FilterListViewModel { // Generate a string based on populated filters, like "instock,publish,simple,clothes" var analyticsDescription: String { - let elements: [String?] = [stockStatus?.rawValue, productStatus?.rawValue, promotableProductType?.productType.rawValue, productCategory?.slug] + let elements: [String?] = [stockStatus?.rawValue, + productStatus?.rawValue, + promotableProductType?.productType.rawValue, + productCategory?.slug, + favoriteProduct?.analyticsDescription] return elements.compactMap { $0 }.joined(separator: ",") } } diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift index 3af41df61ba..6d506f5dd04 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift @@ -3,7 +3,7 @@ import XCTest @testable import Yosemite final class FilterProductListViewModelTests: XCTestCase { - let filterProductCategory = ProductCategory(categoryID: 0, siteID: 0, parentID: 0, name: "", slug: "") + let filterProductCategory = ProductCategory(categoryID: 0, siteID: 0, parentID: 0, name: "", slug: "category") func testCriteriaWithDefaultFilters() { // Given @@ -69,6 +69,21 @@ final class FilterProductListViewModelTests: XCTestCase { XCTAssertEqual(viewModel.criteria, expectedCriteria) } + func test_it_provides_analytics_description_based_on_selected_filters() { + // Given + let filters = FilterProductListViewModel.Filters(stockStatus: .inStock, + productStatus: .draft, + promotableProductType: PromotableProductType(productType: .grouped, + isAvailable: true, + promoteUrl: nil), + productCategory: filterProductCategory, + favoriteProduct: FavoriteProductsFilter(), + numberOfActiveFilters: 5) + + // Then + XCTAssertEqual(filters.analyticsDescription, "instock,draft,grouped,category,favorite_products") + } + // MARK: Favorite product feature flag func test_filterTypeViewModels_does_not_contain_favorite_filter_view_model_when_feature_flag_off() { From bec779ca0a21c99dfb3bf80f5d7959dfe2e5d005 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Wed, 4 Dec 2024 13:05:24 +0530 Subject: [PATCH 2/9] Remove unnecessary MainActor usage to remove Xcode warnings. --- .../Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift | 2 -- .../Products/Edit Product/ProductFormViewModel.swift | 2 -- .../Edit Product/DefaultFavoriteProductsUseCaseTests.swift | 2 -- .../Products/Edit Product/ProductFormViewModelTests.swift | 1 - 4 files changed, 7 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift b/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift index 5af3707e3af..5297487ea8b 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift @@ -47,13 +47,11 @@ struct DefaultFavoriteProductsUseCase: FavoriteProductsUseCase { self.featureFlagService = featureFlagService } - @MainActor func markAsFavorite(productID: Int64) { let action = AppSettingsAction.setProductIDAsFavorite(productID: productID, siteID: siteID) stores.dispatch(action) } - @MainActor func removeFromFavorite(productID: Int64) { let action = AppSettingsAction.removeProductIDAsFavorite(productID: productID, siteID: siteID) stores.dispatch(action) diff --git a/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift index 4b4354d0713..badadb73949 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift @@ -876,12 +876,10 @@ extension ProductFormViewModel { await favoriteProductsUseCase.isFavorite(productID: product.productID) } - @MainActor func markAsFavorite() { favoriteProductsUseCase.markAsFavorite(productID: product.productID) } - @MainActor func removeFromFavorite() { favoriteProductsUseCase.removeFromFavorite(productID: product.productID) } diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/DefaultFavoriteProductsUseCaseTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/DefaultFavoriteProductsUseCaseTests.swift index 3f955242cc8..60a9cd0f17d 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/DefaultFavoriteProductsUseCaseTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/DefaultFavoriteProductsUseCaseTests.swift @@ -16,7 +16,6 @@ final class DefaultFavoriteProductsUseCaseTests: XCTestCase { super.tearDown() } - @MainActor func test_it_sets_product_id_as_favorite_in_app_settings() async { // Given let usecase = DefaultFavoriteProductsUseCase(siteID: sampleSiteID, @@ -39,7 +38,6 @@ final class DefaultFavoriteProductsUseCaseTests: XCTestCase { XCTAssertEqual(receivedProductID, 4) } - @MainActor func test_it_removes_product_id_as_favorite_in_app_settings() async { // Given let usecase = DefaultFavoriteProductsUseCase(siteID: sampleSiteID, diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift index d5d65c39caf..99d00fe3a68 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift @@ -261,7 +261,6 @@ final class ProductFormViewModelTests: XCTestCase { XCTAssertFalse(viewModel.canFavoriteProduct()) } - @MainActor func test_markAsFavorite_marks_product_as_favorite() async { // Given let product = Product.fake() From 5a3185d64d8937980bf54c939681ffcf289af13f Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Wed, 4 Dec 2024 13:12:18 +0530 Subject: [PATCH 3/9] Remove `favoriteProducts` feature flag. --- .../DefaultFeatureFlagService.swift | 2 -- Experiments/Experiments/FeatureFlag.swift | 4 ---- .../FavoriteProductsUseCase.swift | 3 --- .../Edit Product/ProductFormViewModel.swift | 3 --- .../Filters/FilterProductListViewModel.swift | 23 ++++++------------- 5 files changed, 7 insertions(+), 28 deletions(-) diff --git a/Experiments/Experiments/DefaultFeatureFlagService.swift b/Experiments/Experiments/DefaultFeatureFlagService.swift index 390a547b0ab..333e2641862 100644 --- a/Experiments/Experiments/DefaultFeatureFlagService.swift +++ b/Experiments/Experiments/DefaultFeatureFlagService.swift @@ -85,8 +85,6 @@ public struct DefaultFeatureFlagService: FeatureFlagService { return buildConfig == .localDeveloper || buildConfig == .alpha case .blazeCampaignObjective: return true - case .favoriteProducts: - return buildConfig == .localDeveloper || buildConfig == .alpha case .productGlobalUniqueIdentifierSupport: return true case .paymentsOnboardingInPointOfSale: diff --git a/Experiments/Experiments/FeatureFlag.swift b/Experiments/Experiments/FeatureFlag.swift index 9f102b0b568..16202ee3952 100644 --- a/Experiments/Experiments/FeatureFlag.swift +++ b/Experiments/Experiments/FeatureFlag.swift @@ -185,10 +185,6 @@ public enum FeatureFlag: Int { /// case blazeCampaignObjective - /// Allows marking product as favorite - /// - case favoriteProducts - /// Enables support for the new product global unique identifier /// case productGlobalUniqueIdentifierSupport diff --git a/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift b/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift index 5297487ea8b..2ab68ef7841 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift @@ -68,9 +68,6 @@ struct DefaultFavoriteProductsUseCase: FavoriteProductsUseCase { @MainActor func favoriteProductIDs() async -> [Int64] { - guard featureFlagService.isFeatureFlagEnabled(.favoriteProducts) else { - return [] - } return await withCheckedContinuation { continuation in stores.dispatch(AppSettingsAction.loadFavoriteProductIDs(siteID: siteID, onCompletion: { savedFavProductIDs in continuation.resume(returning: savedFavProductIDs) diff --git a/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift index badadb73949..654ee3dbb24 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift @@ -314,9 +314,6 @@ extension ProductFormViewModel { } func canFavoriteProduct() -> Bool { - guard featureFlagService.isFeatureFlagEnabled(.favoriteProducts) else { - return false - } return formType != .add } diff --git a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift index c4abc3c329a..9e9a54e30ed 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift @@ -78,22 +78,13 @@ final class FilterProductListViewModel: FilterListViewModel { self.productCategoryFilterViewModel = ProductListFilter.productCategory(siteID: siteID).createViewModel(filters: filters) self.productFavoriteFilterViewModel = ProductListFilter.favoriteProducts.createViewModel(filters: filters) - if featureFlagService.isFeatureFlagEnabled(.favoriteProducts) { - self.filterTypeViewModels = [ - stockStatusFilterViewModel, - productStatusFilterViewModel, - productTypeFilterViewModel, - productCategoryFilterViewModel, - productFavoriteFilterViewModel - ] - } else { - self.filterTypeViewModels = [ - stockStatusFilterViewModel, - productStatusFilterViewModel, - productTypeFilterViewModel, - productCategoryFilterViewModel, - ] - } + self.filterTypeViewModels = [ + stockStatusFilterViewModel, + productStatusFilterViewModel, + productTypeFilterViewModel, + productCategoryFilterViewModel, + productFavoriteFilterViewModel + ] } var criteria: Filters { From 7ad28442129349495b6a30397f86dd9c3e9ec7fb Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Wed, 4 Dec 2024 13:43:19 +0530 Subject: [PATCH 4/9] Add release notes for favotire products change. --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index d754f74f40a..4444b9750b1 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -21,6 +21,7 @@ - [Internal] Updated storage usage in SitePluginStore [https://github.com/woocommerce/woocommerce-ios/pull/14560] - [Internal] Updated storage usage in ShippingLabelStore [https://github.com/woocommerce/woocommerce-ios/pull/14566] - [*] Fixed: Improved the error message displayed when Bluetooth permission is denied during the card reader connection process. [https://github.com/woocommerce/woocommerce-ios/pull/14561] +- [*] Merchants can mark and filter favorite products for quicker access. [https://github.com/woocommerce/woocommerce-ios/pull/14597] 21.2 ----- From 04edf72c5f63ccdb02f37060d872896979d9a8b5 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Wed, 4 Dec 2024 13:56:43 +0530 Subject: [PATCH 5/9] Remove feature flag from tests. --- .../Mocks/MockFeatureFlagService.swift | 5 ---- .../ProductFormViewModelTests.swift | 23 +++------------- .../FilterProductListViewModelTests.swift | 27 +------------------ 3 files changed, 5 insertions(+), 50 deletions(-) diff --git a/WooCommerce/WooCommerceTests/Mocks/MockFeatureFlagService.swift b/WooCommerce/WooCommerceTests/Mocks/MockFeatureFlagService.swift index 86c0fe0e997..70a9644f2d2 100644 --- a/WooCommerce/WooCommerceTests/Mocks/MockFeatureFlagService.swift +++ b/WooCommerce/WooCommerceTests/Mocks/MockFeatureFlagService.swift @@ -21,7 +21,6 @@ struct MockFeatureFlagService: FeatureFlagService { private let blazeCampaignObjective: Bool private let revampedShippingLabelCreation: Bool private let viewEditCustomFieldsInProductsAndOrders: Bool - private let favoriteProducts: Bool private let paymentsOnboardingInPointOfSale: Bool private let isProductGlobalUniqueIdentifierSupported: Bool private let isSendReceiptAfterPaymentEnabled: Bool @@ -45,7 +44,6 @@ struct MockFeatureFlagService: FeatureFlagService { blazeCampaignObjective: Bool = false, revampedShippingLabelCreation: Bool = false, viewEditCustomFieldsInProductsAndOrders: Bool = false, - favoriteProducts: Bool = false, paymentsOnboardingInPointOfSale: Bool = false, isProductGlobalUniqueIdentifierSupported: Bool = false, isSendReceiptAfterPaymentEnabled: Bool = false) { @@ -68,7 +66,6 @@ struct MockFeatureFlagService: FeatureFlagService { self.blazeCampaignObjective = blazeCampaignObjective self.revampedShippingLabelCreation = revampedShippingLabelCreation self.viewEditCustomFieldsInProductsAndOrders = viewEditCustomFieldsInProductsAndOrders - self.favoriteProducts = favoriteProducts self.paymentsOnboardingInPointOfSale = paymentsOnboardingInPointOfSale self.isProductGlobalUniqueIdentifierSupported = isProductGlobalUniqueIdentifierSupported self.isSendReceiptAfterPaymentEnabled = isSendReceiptAfterPaymentEnabled @@ -114,8 +111,6 @@ struct MockFeatureFlagService: FeatureFlagService { return revampedShippingLabelCreation case .viewEditCustomFieldsInProductsAndOrders: return viewEditCustomFieldsInProductsAndOrders - case .favoriteProducts: - return favoriteProducts case .paymentsOnboardingInPointOfSale: return paymentsOnboardingInPointOfSale case .productGlobalUniqueIdentifierSupport: diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift index 99d00fe3a68..7f92113bc67 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift @@ -232,8 +232,7 @@ final class ProductFormViewModelTests: XCTestCase { // Given let product = Product.fake() let viewModel = createViewModel(product: product, - formType: .edit, - featureFlagService: MockFeatureFlagService(favoriteProducts: true)) + formType: .edit) // When XCTAssertTrue(viewModel.canFavoriteProduct()) @@ -243,19 +242,7 @@ final class ProductFormViewModelTests: XCTestCase { // Given let product = Product.fake() let viewModel = createViewModel(product: product, - formType: .add, - featureFlagService: MockFeatureFlagService(favoriteProducts: true)) - - // When - XCTAssertFalse(viewModel.canFavoriteProduct()) - } - - func test_canFavoriteProduct_is_false_when_feature_flag_off() { - // Given - let product = Product.fake() - let viewModel = createViewModel(product: product, - formType: .add, - featureFlagService: MockFeatureFlagService(favoriteProducts: false)) + formType: .add) // When XCTAssertFalse(viewModel.canFavoriteProduct()) @@ -267,8 +254,7 @@ final class ProductFormViewModelTests: XCTestCase { let mockUseCase = MockFavoriteProductsUseCase() let viewModel = createViewModel(product: product, formType: .add, - favoriteProductsUseCase: mockUseCase, - featureFlagService: MockFeatureFlagService(favoriteProducts: true)) + favoriteProductsUseCase: mockUseCase) // When viewModel.markAsFavorite() @@ -284,8 +270,7 @@ final class ProductFormViewModelTests: XCTestCase { let mockUseCase = MockFavoriteProductsUseCase() let viewModel = createViewModel(product: product, formType: .add, - favoriteProductsUseCase: mockUseCase, - featureFlagService: MockFeatureFlagService(favoriteProducts: true)) + favoriteProductsUseCase: mockUseCase) // When viewModel.removeFromFavorite() diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift index 6d506f5dd04..49a47c69695 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift @@ -24,7 +24,6 @@ final class FilterProductListViewModelTests: XCTestCase { func test_criteria_with_non_nil_filters_then_it_returns_all_active_filters() { // Given - let featureFlagService = MockFeatureFlagService(favoriteProducts: true) let filters = FilterProductListViewModel.Filters(stockStatus: .inStock, productStatus: .draft, promotableProductType: PromotableProductType(productType: .grouped, @@ -36,8 +35,7 @@ final class FilterProductListViewModelTests: XCTestCase { // When let viewModel = FilterProductListViewModel(filters: filters, - siteID: 0, - featureFlagService: featureFlagService) + siteID: 0) // Then let expectedCriteria = filters @@ -83,27 +81,4 @@ final class FilterProductListViewModelTests: XCTestCase { // Then XCTAssertEqual(filters.analyticsDescription, "instock,draft,grouped,category,favorite_products") } - - // MARK: Favorite product feature flag - - func test_filterTypeViewModels_does_not_contain_favorite_filter_view_model_when_feature_flag_off() { - // Given - let featureFlagService = MockFeatureFlagService(favoriteProducts: false) - let filters = FilterProductListViewModel.Filters(stockStatus: .inStock, - productStatus: .draft, - promotableProductType: PromotableProductType(productType: .grouped, - isAvailable: true, - promoteUrl: nil), - productCategory: filterProductCategory, - favoriteProduct: FavoriteProductsFilter(), - numberOfActiveFilters: 5) - - // When - let viewModel = FilterProductListViewModel(filters: filters, - siteID: 0, - featureFlagService: featureFlagService) - - // Then - XCTAssertFalse(viewModel.filterTypeViewModels.contains(where: { $0.title == FilterProductListViewModel.ProductListFilter.Localization.favoriteProduct } )) - } } From 2d04eb0dbc912d0b0fd7ee21f319e8da4859a87f Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Wed, 4 Dec 2024 14:12:20 +0530 Subject: [PATCH 6/9] Inject mock stores to fix unit tests failing due to main thread error. --- .../Products/Edit Product/ProductFormViewModelTests.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift index 7f92113bc67..188e9c3b373 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift @@ -253,7 +253,8 @@ final class ProductFormViewModelTests: XCTestCase { let product = Product.fake() let mockUseCase = MockFavoriteProductsUseCase() let viewModel = createViewModel(product: product, - formType: .add, + formType: .edit, + stores: stores, favoriteProductsUseCase: mockUseCase) // When @@ -263,13 +264,13 @@ final class ProductFormViewModelTests: XCTestCase { XCTAssertEqual(mockUseCase.markAsFavoriteCalledForProductID, product.productID) } - @MainActor func test_removeFromFavorite_removes_product_as_favorite() async { // Given let product = Product.fake() let mockUseCase = MockFavoriteProductsUseCase() let viewModel = createViewModel(product: product, - formType: .add, + formType: .edit, + stores: stores, favoriteProductsUseCase: mockUseCase) // When From 706316ad819d01c3659863eef9b1c2807fd8eb7f Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Fri, 6 Dec 2024 13:42:13 +0530 Subject: [PATCH 7/9] Revert "Remove feature flag from tests." This reverts commit 04edf72c5f63ccdb02f37060d872896979d9a8b5. --- .../Mocks/MockFeatureFlagService.swift | 5 ++++ .../ProductFormViewModelTests.swift | 23 +++++++++++++--- .../FilterProductListViewModelTests.swift | 27 ++++++++++++++++++- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/WooCommerce/WooCommerceTests/Mocks/MockFeatureFlagService.swift b/WooCommerce/WooCommerceTests/Mocks/MockFeatureFlagService.swift index 70a9644f2d2..86c0fe0e997 100644 --- a/WooCommerce/WooCommerceTests/Mocks/MockFeatureFlagService.swift +++ b/WooCommerce/WooCommerceTests/Mocks/MockFeatureFlagService.swift @@ -21,6 +21,7 @@ struct MockFeatureFlagService: FeatureFlagService { private let blazeCampaignObjective: Bool private let revampedShippingLabelCreation: Bool private let viewEditCustomFieldsInProductsAndOrders: Bool + private let favoriteProducts: Bool private let paymentsOnboardingInPointOfSale: Bool private let isProductGlobalUniqueIdentifierSupported: Bool private let isSendReceiptAfterPaymentEnabled: Bool @@ -44,6 +45,7 @@ struct MockFeatureFlagService: FeatureFlagService { blazeCampaignObjective: Bool = false, revampedShippingLabelCreation: Bool = false, viewEditCustomFieldsInProductsAndOrders: Bool = false, + favoriteProducts: Bool = false, paymentsOnboardingInPointOfSale: Bool = false, isProductGlobalUniqueIdentifierSupported: Bool = false, isSendReceiptAfterPaymentEnabled: Bool = false) { @@ -66,6 +68,7 @@ struct MockFeatureFlagService: FeatureFlagService { self.blazeCampaignObjective = blazeCampaignObjective self.revampedShippingLabelCreation = revampedShippingLabelCreation self.viewEditCustomFieldsInProductsAndOrders = viewEditCustomFieldsInProductsAndOrders + self.favoriteProducts = favoriteProducts self.paymentsOnboardingInPointOfSale = paymentsOnboardingInPointOfSale self.isProductGlobalUniqueIdentifierSupported = isProductGlobalUniqueIdentifierSupported self.isSendReceiptAfterPaymentEnabled = isSendReceiptAfterPaymentEnabled @@ -111,6 +114,8 @@ struct MockFeatureFlagService: FeatureFlagService { return revampedShippingLabelCreation case .viewEditCustomFieldsInProductsAndOrders: return viewEditCustomFieldsInProductsAndOrders + case .favoriteProducts: + return favoriteProducts case .paymentsOnboardingInPointOfSale: return paymentsOnboardingInPointOfSale case .productGlobalUniqueIdentifierSupport: diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift index 188e9c3b373..6624e6f90e0 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Products/Edit Product/ProductFormViewModelTests.swift @@ -232,7 +232,8 @@ final class ProductFormViewModelTests: XCTestCase { // Given let product = Product.fake() let viewModel = createViewModel(product: product, - formType: .edit) + formType: .edit, + featureFlagService: MockFeatureFlagService(favoriteProducts: true)) // When XCTAssertTrue(viewModel.canFavoriteProduct()) @@ -242,7 +243,19 @@ final class ProductFormViewModelTests: XCTestCase { // Given let product = Product.fake() let viewModel = createViewModel(product: product, - formType: .add) + formType: .add, + featureFlagService: MockFeatureFlagService(favoriteProducts: true)) + + // When + XCTAssertFalse(viewModel.canFavoriteProduct()) + } + + func test_canFavoriteProduct_is_false_when_feature_flag_off() { + // Given + let product = Product.fake() + let viewModel = createViewModel(product: product, + formType: .add, + featureFlagService: MockFeatureFlagService(favoriteProducts: false)) // When XCTAssertFalse(viewModel.canFavoriteProduct()) @@ -255,7 +268,8 @@ final class ProductFormViewModelTests: XCTestCase { let viewModel = createViewModel(product: product, formType: .edit, stores: stores, - favoriteProductsUseCase: mockUseCase) + favoriteProductsUseCase: mockUseCase, + featureFlagService: MockFeatureFlagService(favoriteProducts: true)) // When viewModel.markAsFavorite() @@ -271,7 +285,8 @@ final class ProductFormViewModelTests: XCTestCase { let viewModel = createViewModel(product: product, formType: .edit, stores: stores, - favoriteProductsUseCase: mockUseCase) + favoriteProductsUseCase: mockUseCase, + featureFlagService: MockFeatureFlagService(favoriteProducts: true)) // When viewModel.removeFromFavorite() diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift index 49a47c69695..6d506f5dd04 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Products/Filters/FilterProductListViewModelTests.swift @@ -24,6 +24,7 @@ final class FilterProductListViewModelTests: XCTestCase { func test_criteria_with_non_nil_filters_then_it_returns_all_active_filters() { // Given + let featureFlagService = MockFeatureFlagService(favoriteProducts: true) let filters = FilterProductListViewModel.Filters(stockStatus: .inStock, productStatus: .draft, promotableProductType: PromotableProductType(productType: .grouped, @@ -35,7 +36,8 @@ final class FilterProductListViewModelTests: XCTestCase { // When let viewModel = FilterProductListViewModel(filters: filters, - siteID: 0) + siteID: 0, + featureFlagService: featureFlagService) // Then let expectedCriteria = filters @@ -81,4 +83,27 @@ final class FilterProductListViewModelTests: XCTestCase { // Then XCTAssertEqual(filters.analyticsDescription, "instock,draft,grouped,category,favorite_products") } + + // MARK: Favorite product feature flag + + func test_filterTypeViewModels_does_not_contain_favorite_filter_view_model_when_feature_flag_off() { + // Given + let featureFlagService = MockFeatureFlagService(favoriteProducts: false) + let filters = FilterProductListViewModel.Filters(stockStatus: .inStock, + productStatus: .draft, + promotableProductType: PromotableProductType(productType: .grouped, + isAvailable: true, + promoteUrl: nil), + productCategory: filterProductCategory, + favoriteProduct: FavoriteProductsFilter(), + numberOfActiveFilters: 5) + + // When + let viewModel = FilterProductListViewModel(filters: filters, + siteID: 0, + featureFlagService: featureFlagService) + + // Then + XCTAssertFalse(viewModel.filterTypeViewModels.contains(where: { $0.title == FilterProductListViewModel.ProductListFilter.Localization.favoriteProduct } )) + } } From 0a0ce1d6a3135af7023abeaefe7e89253c844482 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Fri, 6 Dec 2024 13:42:23 +0530 Subject: [PATCH 8/9] Revert "Remove `favoriteProducts` feature flag." This reverts commit 5a3185d64d8937980bf54c939681ffcf289af13f. --- .../DefaultFeatureFlagService.swift | 2 ++ Experiments/Experiments/FeatureFlag.swift | 4 ++++ .../FavoriteProductsUseCase.swift | 3 +++ .../Edit Product/ProductFormViewModel.swift | 3 +++ .../Filters/FilterProductListViewModel.swift | 23 +++++++++++++------ 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Experiments/Experiments/DefaultFeatureFlagService.swift b/Experiments/Experiments/DefaultFeatureFlagService.swift index 333e2641862..390a547b0ab 100644 --- a/Experiments/Experiments/DefaultFeatureFlagService.swift +++ b/Experiments/Experiments/DefaultFeatureFlagService.swift @@ -85,6 +85,8 @@ public struct DefaultFeatureFlagService: FeatureFlagService { return buildConfig == .localDeveloper || buildConfig == .alpha case .blazeCampaignObjective: return true + case .favoriteProducts: + return buildConfig == .localDeveloper || buildConfig == .alpha case .productGlobalUniqueIdentifierSupport: return true case .paymentsOnboardingInPointOfSale: diff --git a/Experiments/Experiments/FeatureFlag.swift b/Experiments/Experiments/FeatureFlag.swift index 16202ee3952..9f102b0b568 100644 --- a/Experiments/Experiments/FeatureFlag.swift +++ b/Experiments/Experiments/FeatureFlag.swift @@ -185,6 +185,10 @@ public enum FeatureFlag: Int { /// case blazeCampaignObjective + /// Allows marking product as favorite + /// + case favoriteProducts + /// Enables support for the new product global unique identifier /// case productGlobalUniqueIdentifierSupport diff --git a/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift b/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift index 2ab68ef7841..5297487ea8b 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Edit Product/FavoriteProducts/FavoriteProductsUseCase.swift @@ -68,6 +68,9 @@ struct DefaultFavoriteProductsUseCase: FavoriteProductsUseCase { @MainActor func favoriteProductIDs() async -> [Int64] { + guard featureFlagService.isFeatureFlagEnabled(.favoriteProducts) else { + return [] + } return await withCheckedContinuation { continuation in stores.dispatch(AppSettingsAction.loadFavoriteProductIDs(siteID: siteID, onCompletion: { savedFavProductIDs in continuation.resume(returning: savedFavProductIDs) diff --git a/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift index 654ee3dbb24..badadb73949 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewModel.swift @@ -314,6 +314,9 @@ extension ProductFormViewModel { } func canFavoriteProduct() -> Bool { + guard featureFlagService.isFeatureFlagEnabled(.favoriteProducts) else { + return false + } return formType != .add } diff --git a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift index 9e9a54e30ed..c4abc3c329a 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift @@ -78,13 +78,22 @@ final class FilterProductListViewModel: FilterListViewModel { self.productCategoryFilterViewModel = ProductListFilter.productCategory(siteID: siteID).createViewModel(filters: filters) self.productFavoriteFilterViewModel = ProductListFilter.favoriteProducts.createViewModel(filters: filters) - self.filterTypeViewModels = [ - stockStatusFilterViewModel, - productStatusFilterViewModel, - productTypeFilterViewModel, - productCategoryFilterViewModel, - productFavoriteFilterViewModel - ] + if featureFlagService.isFeatureFlagEnabled(.favoriteProducts) { + self.filterTypeViewModels = [ + stockStatusFilterViewModel, + productStatusFilterViewModel, + productTypeFilterViewModel, + productCategoryFilterViewModel, + productFavoriteFilterViewModel + ] + } else { + self.filterTypeViewModels = [ + stockStatusFilterViewModel, + productStatusFilterViewModel, + productTypeFilterViewModel, + productCategoryFilterViewModel, + ] + } } var criteria: Filters { From b593f4b77eb0af37c8772d775aceabf30f23d38b Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Fri, 6 Dec 2024 13:50:24 +0530 Subject: [PATCH 9/9] Enable favorite products feature flag. --- Experiments/Experiments/DefaultFeatureFlagService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experiments/Experiments/DefaultFeatureFlagService.swift b/Experiments/Experiments/DefaultFeatureFlagService.swift index 390a547b0ab..5fbfb97203e 100644 --- a/Experiments/Experiments/DefaultFeatureFlagService.swift +++ b/Experiments/Experiments/DefaultFeatureFlagService.swift @@ -86,7 +86,7 @@ public struct DefaultFeatureFlagService: FeatureFlagService { case .blazeCampaignObjective: return true case .favoriteProducts: - return buildConfig == .localDeveloper || buildConfig == .alpha + return true case .productGlobalUniqueIdentifierSupport: return true case .paymentsOnboardingInPointOfSale: