diff --git a/firefox-ios/Providers/Merino/MerinoProvider.swift b/firefox-ios/Providers/Merino/MerinoProvider.swift index 254686102b9b..b8409137b477 100644 --- a/firefox-ios/Providers/Merino/MerinoProvider.swift +++ b/firefox-ios/Providers/Merino/MerinoProvider.swift @@ -48,7 +48,10 @@ final class MerinoProvider: MerinoStoriesProviding, FeatureFlaggable, @unchecked func fetchContent() async throws -> CuratedRecommendationsResponse { if !AppConstants.isRunningTest && shouldUseMockData { - return MerinoTestData().getMockDataFeed(Constants.numberOfStoriesToFetchForCaching) + return MerinoTestData().getMockDataFeed( + Constants.numberOfStoriesToFetchForCaching, + categoriesEnabled: isHomepageStoryCategoriesEnabled + ) } guard prefs.boolForKey(PrefsKeys.UserFeatureFlagPrefs.ASPocketStories) ?? true, @@ -113,6 +116,10 @@ final class MerinoProvider: MerinoStoriesProviding, FeatureFlaggable, @unchecked return featureFlags.isCoreFeatureEnabled(.useMockData) || prefs.boolForKey(PrefsKeys.useMerinoTestData) ?? false } + private var isHomepageStoryCategoriesEnabled: Bool { + return featureFlags.isFeatureEnabled(.homepageStoryCategories, checking: .buildOnly) + } + private func iOSToMerinoLocale(from locale: String) -> CuratedRecommendationLocale? { return curatedRecommendationLocaleFromString( locale: locale.replacingOccurrences(of: "_", with: "-") @@ -130,9 +137,7 @@ final class MerinoProvider: MerinoStoriesProviding, FeatureFlaggable, @unchecked /// non-empty top-level story `data`. If the shapes do not match, we bypass the cache /// and fetch again so a mode switch is reflected immediately. private func cachedResponseMatchesCurrentHomepageStoriesMode(_ response: CuratedRecommendationsResponse) -> Bool { - let categoriesEnabled = featureFlags.isFeatureEnabled(.homepageStoryCategories, checking: .buildOnly) - - if categoriesEnabled { + if isHomepageStoryCategoriesEnabled { return !(response.feeds?.isEmpty ?? true) } diff --git a/firefox-ios/Providers/Merino/MerinoTestData.swift b/firefox-ios/Providers/Merino/MerinoTestData.swift index 0f0927cea069..b82ca0b11275 100644 --- a/firefox-ios/Providers/Merino/MerinoTestData.swift +++ b/firefox-ios/Providers/Merino/MerinoTestData.swift @@ -8,7 +8,7 @@ import MozillaAppServices struct MerinoTestData { /// Because we're not testing the Merino API/AS module, we're simply providing some /// dummy data here. - func getMockDataFeed(_ numberOfStories: Int) -> CuratedRecommendationsResponse { + func getMockDataFeed(_ numberOfStories: Int, categoriesEnabled: Bool = false) -> CuratedRecommendationsResponse { var mockData = mockFeedData(startingRank: 0) while mockData.count < numberOfStories { mockData.append(contentsOf: mockFeedData(startingRank: Int64(mockData.count))) @@ -16,13 +16,43 @@ struct MerinoTestData { return CuratedRecommendationsResponse( recommendedAt: 123, - data: mockData, - feeds: mockCategoryData() + data: categoriesEnabled ? [] : mockData, + feeds: categoriesEnabled ? mockCategoryData() : nil ) } private func mockCategoryData() -> [FeedSection] { - return [] + let stories = mockFeedData(startingRank: 0) + + return [ + FeedSection( + feedId: "travel", + receivedFeedRank: 0, + recommendations: Array(stories[0..<4]), + title: "Travel", + layout: Layout(name: "", responsiveLayouts: []), + isFollowed: false, + isBlocked: false + ), + FeedSection( + feedId: "technology", + receivedFeedRank: 1, + recommendations: Array(stories[4..<7]), + title: "Technology", + layout: Layout(name: "", responsiveLayouts: []), + isFollowed: false, + isBlocked: false + ), + FeedSection( + feedId: "science", + receivedFeedRank: 2, + recommendations: Array(stories[7..<10]), + title: "Science", + layout: Layout(name: "4", responsiveLayouts: []), + isFollowed: false, + isBlocked: false + ), + ] } private func mockFeedData(startingRank: Int64) -> [RecommendationDataItem] { diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/Merino/MerinoProviderTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Merino/MerinoProviderTests.swift index c534cd58b4d7..5924de3e16b6 100644 --- a/firefox-ios/firefox-ios-tests/Tests/ClientTests/Merino/MerinoProviderTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Merino/MerinoProviderTests.swift @@ -311,6 +311,23 @@ final class MerinoProviderTests: XCTestCase, @unchecked Sendable { XCTAssertEqual(control.fetcher.callCount, 1) } + func test_getMockDataFeed_whenCategoriesDisabled_returnsStoriesOnly() { + let response = MerinoTestData().getMockDataFeed(10, categoriesEnabled: false) + + XCTAssertEqual(response.data.count, 10) + XCTAssertNil(response.feeds) + } + + func test_getMockDataFeed_whenCategoriesEnabled_returnsFeedsOnly() { + let response = MerinoTestData().getMockDataFeed(10, categoriesEnabled: true) + let categoryRecommendations = response.feeds?.flatMap(\.recommendations) ?? [] + + XCTAssertEqual(response.data.count, 0) + XCTAssertEqual(response.feeds?.map(\.feedId), ["travel", "technology", "science"]) + XCTAssertEqual(response.feeds?.allSatisfy { !$0.recommendations.isEmpty }, true) + XCTAssertEqual(categoryRecommendations.count, 10) + } + private func createSubject( thresholdHours: Double = 4, prefsEnabled: Bool = true,