diff --git a/remote-messaging/remote-messaging-api/src/main/java/com/duckduckgo/remote/messaging/api/RemoteMessage.kt b/remote-messaging/remote-messaging-api/src/main/java/com/duckduckgo/remote/messaging/api/RemoteMessage.kt index 013c69fbbe79..e5f2295c9b1c 100644 --- a/remote-messaging/remote-messaging-api/src/main/java/com/duckduckgo/remote/messaging/api/RemoteMessage.kt +++ b/remote-messaging/remote-messaging-api/src/main/java/com/duckduckgo/remote/messaging/api/RemoteMessage.kt @@ -155,6 +155,8 @@ data class CardItem( val descriptionText: String, val placeholder: Placeholder, val primaryAction: Action, + val matchingRules: List, + val exclusionRules: List, ) enum class CardItemType(val jsonValue: String) { diff --git a/remote-messaging/remote-messaging-impl/src/main/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigMatcher.kt b/remote-messaging/remote-messaging-impl/src/main/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigMatcher.kt index 89f8e59a2d3b..a0be55c2db49 100644 --- a/remote-messaging/remote-messaging-impl/src/main/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigMatcher.kt +++ b/remote-messaging/remote-messaging-impl/src/main/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigMatcher.kt @@ -17,6 +17,7 @@ package com.duckduckgo.remote.messaging.impl import com.duckduckgo.remote.messaging.api.AttributeMatcherPlugin +import com.duckduckgo.remote.messaging.api.Content import com.duckduckgo.remote.messaging.api.MatchingAttribute import com.duckduckgo.remote.messaging.api.RemoteMessage import com.duckduckgo.remote.messaging.api.RemoteMessagingRepository @@ -40,17 +41,63 @@ class RemoteMessagingConfigMatcher( val dismissedMessages = remoteMessagingRepository.dismissedMessages() remoteConfig.messages.filter { !dismissedMessages.contains(it.id) }.forEach { message -> - val matchingRules = if (message.matchingRules.isEmpty() && message.exclusionRules.isEmpty()) return message else message.matchingRules + val matchingRules = if (message.matchingRules.isEmpty() && message.exclusionRules.isEmpty()) { + val processed = filterCardsListMessage(message, rules) + if (processed != null) return processed + return@forEach + } else { + message.matchingRules + } val matchingResult = matchingRules.evaluateMatchingRules(message.id, rules) val excludeResult = message.exclusionRules.evaluateExclusionRules(message.id, rules) - if (matchingResult == EvaluationResult.Match && excludeResult == EvaluationResult.Fail) return message + if (matchingResult == EvaluationResult.Match && excludeResult == EvaluationResult.Fail) { + val processed = filterCardsListMessage(message, rules) + if (processed != null) return processed + return@forEach + } } return null } + private suspend fun filterCardsListMessage( + message: RemoteMessage, + rules: List, + ): RemoteMessage? { + val cardsList = message.content as? Content.CardsList ?: return message + + val filteredItems = cardsList.listItems.filter { cardItem -> + if (cardItem.matchingRules.isEmpty() && cardItem.exclusionRules.isEmpty()) { + true + } else { + // Evaluate CardItem rules following the same logic as for remote message + val itemMatching = if (cardItem.matchingRules.isEmpty()) { + EvaluationResult.Match + } else { + cardItem.matchingRules.evaluateMatchingRules(message.id, rules) + } + + val itemExclusion = if (cardItem.exclusionRules.isEmpty()) { + EvaluationResult.Fail + } else { + cardItem.exclusionRules.evaluateExclusionRules(message.id, rules) + } + + itemMatching == EvaluationResult.Match && itemExclusion == EvaluationResult.Fail + } + } + + if (filteredItems.isEmpty()) { + logcat(INFO) { "RMF: All CardItems filtered out for message ${message.id}. Nothing to display." } + return null + } + + logcat(INFO) { "RMF: Filtered ${cardsList.listItems.size - filteredItems.size} CardItems for message ${message.id}." } + return message.copy(content = cardsList.copy(listItems = filteredItems)) + } + private suspend fun Iterable.evaluateMatchingRules( messageId: String, rules: List, diff --git a/remote-messaging/remote-messaging-impl/src/main/java/com/duckduckgo/remote/messaging/impl/mappers/JsonRemoteMessageMapper.kt b/remote-messaging/remote-messaging-impl/src/main/java/com/duckduckgo/remote/messaging/impl/mappers/JsonRemoteMessageMapper.kt index 79cd90fedcf9..75187b2c35a9 100644 --- a/remote-messaging/remote-messaging-impl/src/main/java/com/duckduckgo/remote/messaging/impl/mappers/JsonRemoteMessageMapper.kt +++ b/remote-messaging/remote-messaging-impl/src/main/java/com/duckduckgo/remote/messaging/impl/mappers/JsonRemoteMessageMapper.kt @@ -185,6 +185,8 @@ private fun List?.toListItems(actionMappers: Set = emptyList(), + val exclusionRules: List = emptyList(), ) @Suppress("ktlint:standard:class-naming") diff --git a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/fixtures/RemoteMessageOM.kt b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/fixtures/RemoteMessageOM.kt index 755fee195857..c0670acb7677 100644 --- a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/fixtures/RemoteMessageOM.kt +++ b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/fixtures/RemoteMessageOM.kt @@ -112,6 +112,8 @@ object RemoteMessageOM { descriptionText = "Item Description 1", placeholder = IMAGE_AI, primaryAction = urlAction(), + matchingRules = emptyList(), + exclusionRules = emptyList(), ), CardItem( id = "item2", @@ -120,6 +122,8 @@ object RemoteMessageOM { descriptionText = "Item Description 2", placeholder = RADAR, primaryAction = urlAction(), + matchingRules = emptyList(), + exclusionRules = emptyList(), ), ), ) = Content.CardsList( diff --git a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/CardsListMessageMapperTest.kt b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/CardsListMessageMapperTest.kt index a1ace46ff4e2..433483939db4 100644 --- a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/CardsListMessageMapperTest.kt +++ b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/CardsListMessageMapperTest.kt @@ -325,4 +325,85 @@ class CardsListMessageMapperTest { assertEquals("Share this!", shareAction.value) assertEquals("Share Title", shareAction.title) } + + @Test + fun whenCardsListMessageWithMatchingAndExclusionRulesThenMapCorrectly() { + val listItemsWithRules = listOf( + JsonListItem( + id = "item1", + type = "two_line_list_item", + titleText = "Feature One", + descriptionText = "First feature", + placeholder = "ImageAI", + primaryAction = JsonMessageAction(type = "url", value = "https://example.com/1", additionalParameters = null), + matchingRules = listOf(1, 2, 3), + exclusionRules = listOf(4, 5), + ), + JsonListItem( + id = "item2", + type = "two_line_list_item", + titleText = "Feature Two", + descriptionText = "Second feature", + placeholder = "Radar", + primaryAction = JsonMessageAction(type = "url", value = "https://example.com/2", additionalParameters = null), + matchingRules = listOf(6), + exclusionRules = emptyList(), + ), + ) + + val jsonMessages = listOf( + aJsonMessage( + id = "cards10", + content = cardsListJsonContent(listItems = listItemsWithRules), + ), + ) + + val remoteMessages = jsonMessages.mapToRemoteMessage(Locale.US, messageActionPlugins) + + assertEquals(1, remoteMessages.size) + val content = remoteMessages.first().content as Content.CardsList + assertEquals(2, content.listItems.size) + + val item1 = content.listItems[0] + assertEquals("item1", item1.id) + assertEquals(listOf(1, 2, 3), item1.matchingRules) + assertEquals(listOf(4, 5), item1.exclusionRules) + + val item2 = content.listItems[1] + assertEquals("item2", item2.id) + assertEquals(listOf(6), item2.matchingRules) + assertEquals(emptyList(), item2.exclusionRules) + } + + @Test + fun whenCardsListMessageWithoutRulesThenDefaultToEmptyLists() { + val listItemsWithoutRules = listOf( + JsonListItem( + id = "item1", + type = "two_line_list_item", + titleText = "Feature", + descriptionText = "Description", + placeholder = "ImageAI", + primaryAction = JsonMessageAction(type = "url", value = "https://example.com", additionalParameters = null), + ), + ) + + val jsonMessages = listOf( + aJsonMessage( + id = "cards11", + content = cardsListJsonContent(listItems = listItemsWithoutRules), + ), + ) + + val remoteMessages = jsonMessages.mapToRemoteMessage(Locale.US, messageActionPlugins) + + assertEquals(1, remoteMessages.size) + val content = remoteMessages.first().content as Content.CardsList + assertEquals(1, content.listItems.size) + + val item = content.listItems[0] + assertEquals("item1", item.id) + assertEquals(emptyList(), item.matchingRules) + assertEquals(emptyList(), item.exclusionRules) + } } diff --git a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigJsonMapperTest.kt b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigJsonMapperTest.kt index 4c0bc276ccc4..717e323cf3b9 100644 --- a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigJsonMapperTest.kt +++ b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigJsonMapperTest.kt @@ -289,6 +289,8 @@ class RemoteMessagingConfigJsonMapperTest { primaryAction = Action.UrlInContext( value = "https://duckduckgo.com/duckduckgo-help-pages/results/how-to-filter-out-ai-images-in-duckduckgo-search-results", ), + matchingRules = emptyList(), + exclusionRules = emptyList(), ), CardItem( id = "enhanced_scam_blocker", @@ -299,6 +301,8 @@ class RemoteMessagingConfigJsonMapperTest { primaryAction = Action.UrlInContext( value = "https://spreadprivacy.com/scam-blocker/", ), + matchingRules = emptyList(), + exclusionRules = emptyList(), ), CardItem( id = "import_passwords", @@ -307,6 +311,8 @@ class RemoteMessagingConfigJsonMapperTest { descriptionText = "Use DuckDuckGo to manage passwords on apps and sites across your whole device.", placeholder = Content.Placeholder.KEY_IMPORT, primaryAction = Action.DefaultCredentialProvider, + matchingRules = emptyList(), + exclusionRules = emptyList(), ), ), ), diff --git a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigMatcherTest.kt b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigMatcherTest.kt index a99a6f5a97d4..eaf28faff833 100644 --- a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigMatcherTest.kt +++ b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/RemoteMessagingConfigMatcherTest.kt @@ -20,11 +20,17 @@ import androidx.room.Room import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.remote.messaging.api.Action import com.duckduckgo.remote.messaging.api.AttributeMatcherPlugin +import com.duckduckgo.remote.messaging.api.CardItem +import com.duckduckgo.remote.messaging.api.CardItemType +import com.duckduckgo.remote.messaging.api.Content import com.duckduckgo.remote.messaging.api.MatchingAttribute import com.duckduckgo.remote.messaging.api.RemoteMessagingRepository +import com.duckduckgo.remote.messaging.fixtures.RemoteMessageOM.aCardsListMessage import com.duckduckgo.remote.messaging.fixtures.RemoteMessageOM.aMediumMessage import com.duckduckgo.remote.messaging.fixtures.RemoteMessageOM.aSmallMessage +import com.duckduckgo.remote.messaging.fixtures.RemoteMessageOM.cardsListContent import com.duckduckgo.remote.messaging.impl.models.* import com.duckduckgo.remote.messaging.impl.models.RemoteConfig import com.duckduckgo.remote.messaging.store.RemoteMessagingCohort @@ -435,6 +441,254 @@ class RemoteMessagingConfigMatcherTest { assertEquals(aMediumMessage(id = "message1", exclusionRules = rules(2)), message) } + @Test + fun whenCardsListMessageWithNoRulesAndCardItemsWithNoRulesThenReturnsMessageWithAllItems() = runBlocking { + val cardItem1 = CardItem( + id = "item1", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Card 1", + descriptionText = "Description 1", + placeholder = Content.Placeholder.DDG_ANNOUNCE, + primaryAction = Action.Dismiss, + matchingRules = emptyList(), + exclusionRules = emptyList(), + ) + val cardItem2 = CardItem( + id = "item2", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Card 2", + descriptionText = "Description 2", + placeholder = Content.Placeholder.RADAR, + primaryAction = Action.Dismiss, + matchingRules = emptyList(), + exclusionRules = emptyList(), + ) + val cardsListContent = cardsListContent(listItems = listOf(cardItem1, cardItem2)) + val message = aCardsListMessage(content = cardsListContent) + + val result = testee.evaluate( + RemoteConfig( + messages = listOf(message), + rules = emptyList(), + ), + ) + + assertEquals(message, result) + } + + @Test + fun whenCardsListMessageWithSomeCardItemsPassingRulesThenReturnsFilteredMessage() = runBlocking { + givenDeviceMatches(Api(max = 19)) + val passingItem = CardItem( + id = "passing", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Passing Card", + descriptionText = "Description", + placeholder = Content.Placeholder.DDG_ANNOUNCE, + primaryAction = Action.Dismiss, + matchingRules = rules(1), + exclusionRules = emptyList(), + ) + val failingItem1 = CardItem( + id = "failing1", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Failing Card 1", + descriptionText = "Description", + placeholder = Content.Placeholder.RADAR, + primaryAction = Action.Dismiss, + matchingRules = rules(2), + exclusionRules = emptyList(), + ) + val failingItem2 = CardItem( + id = "failing2", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Failing Card 2", + descriptionText = "Description", + placeholder = Content.Placeholder.IMAGE_AI, + primaryAction = Action.Dismiss, + matchingRules = rules(2), + exclusionRules = emptyList(), + ) + val cardsListContent = cardsListContent(listItems = listOf(passingItem, failingItem1, failingItem2)) + val message = aCardsListMessage(content = cardsListContent) + + val result = testee.evaluate( + RemoteConfig( + messages = listOf(message), + rules = listOf( + rule(id = 1, matchingAttributes = arrayOf(Api(max = 19))), + rule(id = 2, matchingAttributes = arrayOf(Api(max = 15))), + ), + ), + ) + + val expectedContent = cardsListContent.copy(listItems = listOf(passingItem)) + assertEquals(message.copy(content = expectedContent), result) + } + + @Test + fun whenCardsListMessageWithAllCardItemsFailingRulesThenReturnsNull() = runBlocking { + givenDeviceMatches(Api(max = 19)) + val failingItem1 = CardItem( + id = "failing1", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Failing Card 1", + descriptionText = "Description", + placeholder = Content.Placeholder.DDG_ANNOUNCE, + primaryAction = Action.Dismiss, + matchingRules = rules(1), + exclusionRules = emptyList(), + ) + val failingItem2 = CardItem( + id = "failing2", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Failing Card 2", + descriptionText = "Description", + placeholder = Content.Placeholder.RADAR, + primaryAction = Action.Dismiss, + matchingRules = rules(1), + exclusionRules = emptyList(), + ) + val cardsListContent = cardsListContent(listItems = listOf(failingItem1, failingItem2)) + val message = aCardsListMessage(content = cardsListContent) + + val result = testee.evaluate( + RemoteConfig( + messages = listOf(message), + rules = listOf( + rule(id = 1, matchingAttributes = arrayOf(Api(max = 15))), + ), + ), + ) + + assertNull(result) + } + + @Test + fun whenCardsListMessageWithCardItemsWithNoRulesThenReturnsAllItems() = runBlocking { + givenDeviceMatches(Api(max = 19)) + val cardItem1 = CardItem( + id = "item1", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Card 1", + descriptionText = "Description 1", + placeholder = Content.Placeholder.DDG_ANNOUNCE, + primaryAction = Action.Dismiss, + matchingRules = emptyList(), + exclusionRules = emptyList(), + ) + val cardItem2 = CardItem( + id = "item2", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Card 2", + descriptionText = "Description 2", + placeholder = Content.Placeholder.RADAR, + primaryAction = Action.Dismiss, + matchingRules = emptyList(), + exclusionRules = emptyList(), + ) + val cardsListContent = cardsListContent(listItems = listOf(cardItem1, cardItem2)) + val message = aCardsListMessage(content = cardsListContent, matchingRules = rules(1)) + + val result = testee.evaluate( + RemoteConfig( + messages = listOf(message), + rules = listOf( + rule(id = 1, matchingAttributes = arrayOf(Api(max = 19))), + ), + ), + ) + + assertEquals(message, result) + } + + @Test + fun whenCardsListMessageWithCardItemMatchingExclusionRuleThenItemFiltered() = runBlocking { + givenDeviceMatches(Api(max = 19), Locale(value = listOf("en-US"))) + val passingItem = CardItem( + id = "passing", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Passing Card", + descriptionText = "Description", + placeholder = Content.Placeholder.DDG_ANNOUNCE, + primaryAction = Action.Dismiss, + matchingRules = rules(1), + exclusionRules = rules(3), + ) + val excludedItem = CardItem( + id = "excluded", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Excluded Card", + descriptionText = "Description", + placeholder = Content.Placeholder.RADAR, + primaryAction = Action.Dismiss, + matchingRules = rules(1), + exclusionRules = rules(2), + ) + val cardsListContent = cardsListContent(listItems = listOf(passingItem, excludedItem)) + val message = aCardsListMessage(content = cardsListContent) + + val result = testee.evaluate( + RemoteConfig( + messages = listOf(message), + rules = listOf( + rule(id = 1, matchingAttributes = arrayOf(Api(max = 19))), + rule(id = 2, matchingAttributes = arrayOf(Locale(value = listOf("en-US")))), + rule(id = 3, matchingAttributes = arrayOf(EmailEnabled(value = true))), + ), + ), + ) + + val expectedContent = cardsListContent.copy(listItems = listOf(passingItem)) + assertEquals(message.copy(content = expectedContent), result) + } + + @Test + fun whenNonCardsListMessageThenReturnsMessageUnmodified() = runBlocking { + givenDeviceMatches(Api(max = 19)) + val message = aMediumMessage(matchingRules = rules(1)) + + val result = testee.evaluate( + RemoteConfig( + messages = listOf(message), + rules = listOf( + rule(id = 1, matchingAttributes = arrayOf(Api(max = 19))), + ), + ), + ) + + assertEquals(message, result) + } + + @Test + fun whenCardsListMessageFailsOwnRulesThenReturnsNullWithoutCheckingCardItems() = runBlocking { + givenDeviceMatches(Api(max = 19)) + val cardItem = CardItem( + id = "item1", + type = CardItemType.TWO_LINE_LIST_ITEM, + titleText = "Card 1", + descriptionText = "Description 1", + placeholder = Content.Placeholder.DDG_ANNOUNCE, + primaryAction = Action.Dismiss, + matchingRules = rules(1), + exclusionRules = emptyList(), + ) + val cardsListContent = cardsListContent(listItems = listOf(cardItem)) + val message = aCardsListMessage(content = cardsListContent, matchingRules = rules(2)) + + val result = testee.evaluate( + RemoteConfig( + messages = listOf(message), + rules = listOf( + rule(id = 1, matchingAttributes = arrayOf(Api(max = 19))), + rule(id = 2, matchingAttributes = arrayOf(Api(max = 15))), + ), + ), + ) + + assertNull(result) + } + private suspend fun givenDeviceMatches( vararg matchingAttributes: MatchingAttribute, ) { diff --git a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/CardsListRemoteMessageViewModelTest.kt b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/CardsListRemoteMessageViewModelTest.kt index 4eb56181cf77..4d85142df567 100644 --- a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/CardsListRemoteMessageViewModelTest.kt +++ b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/CardsListRemoteMessageViewModelTest.kt @@ -101,6 +101,8 @@ class CardsListRemoteMessageViewModelTest { titleText = "Card 1", descriptionText = "Description 1", primaryAction = Action.Dismiss, + matchingRules = emptyList(), + exclusionRules = emptyList(), ), ), primaryActionText = "Dismiss", @@ -188,6 +190,8 @@ class CardsListRemoteMessageViewModelTest { titleText = "Card 1", descriptionText = "Description 1", primaryAction = Action.Dismiss, + matchingRules = emptyList(), + exclusionRules = emptyList(), ) val cardItem2 = CardItem( id = "item2", @@ -196,6 +200,8 @@ class CardsListRemoteMessageViewModelTest { titleText = "Card 2", descriptionText = "Description 2", primaryAction = Action.Dismiss, + matchingRules = emptyList(), + exclusionRules = emptyList(), ) val cardsList = Content.CardsList( titleText = "Test Cards", @@ -328,6 +334,8 @@ class CardsListRemoteMessageViewModelTest { primaryAction = itemAction, placeholder = Content.Placeholder.DDG_ANNOUNCE, type = CardItemType.TWO_LINE_LIST_ITEM, + matchingRules = emptyList(), + exclusionRules = emptyList(), ) val expectedCommand = Command.LaunchPlayStore("com.example.app") whenever(commandActionMapper.asCommand(eq(itemAction))).thenReturn(expectedCommand) @@ -352,6 +360,8 @@ class CardsListRemoteMessageViewModelTest { primaryAction = itemAction, placeholder = Content.Placeholder.DDG_ANNOUNCE, type = CardItemType.TWO_LINE_LIST_ITEM, + matchingRules = emptyList(), + exclusionRules = emptyList(), ) val cardsList = Content.CardsList( titleText = "Test Cards", @@ -399,6 +409,8 @@ class CardsListRemoteMessageViewModelTest { primaryAction = itemAction1, type = CardItemType.TWO_LINE_LIST_ITEM, placeholder = Content.Placeholder.DDG_ANNOUNCE, + matchingRules = emptyList(), + exclusionRules = emptyList(), ) val cardItem2 = CardItem( id = "id2", @@ -407,6 +419,8 @@ class CardsListRemoteMessageViewModelTest { primaryAction = itemAction2, type = CardItemType.TWO_LINE_LIST_ITEM, placeholder = Content.Placeholder.DDG_ANNOUNCE, + matchingRules = emptyList(), + exclusionRules = emptyList(), ) val cardsList = Content.CardsList( titleText = "Test Cards", @@ -456,6 +470,8 @@ class CardsListRemoteMessageViewModelTest { primaryAction = action, type = CardItemType.TWO_LINE_LIST_ITEM, placeholder = Content.Placeholder.DDG_ANNOUNCE, + matchingRules = emptyList(), + exclusionRules = emptyList(), ) val cardsList = Content.CardsList( titleText = "Test Cards", diff --git a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/RealCardsListRemoteMessagePixelHelperTest.kt b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/RealCardsListRemoteMessagePixelHelperTest.kt index 332184dd22c9..626aeb79398c 100644 --- a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/RealCardsListRemoteMessagePixelHelperTest.kt +++ b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/RealCardsListRemoteMessagePixelHelperTest.kt @@ -68,6 +68,8 @@ class RealCardsListRemoteMessagePixelHelperTest { primaryAction = Action.Dismiss, type = CardItemType.TWO_LINE_LIST_ITEM, placeholder = Content.Placeholder.DDG_ANNOUNCE, + matchingRules = emptyList(), + exclusionRules = emptyList(), ) @Before diff --git a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/RemoteMessageModalSurfaceEvaluatorImplTest.kt b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/RemoteMessageModalSurfaceEvaluatorImplTest.kt index db5ac0fe3dbd..2d74ede96eff 100644 --- a/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/RemoteMessageModalSurfaceEvaluatorImplTest.kt +++ b/remote-messaging/remote-messaging-impl/src/test/java/com/duckduckgo/remote/messaging/impl/ui/RemoteMessageModalSurfaceEvaluatorImplTest.kt @@ -285,6 +285,8 @@ class RemoteMessageModalSurfaceEvaluatorImplTest { titleText = "Card 1", descriptionText = "Description 1", primaryAction = Action.Dismiss, + matchingRules = emptyList(), + exclusionRules = emptyList(), ), ), ),