343 lines
13 KiB
Kotlin
343 lines
13 KiB
Kotlin
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
package org.mozilla.fenix.gleanplumb.state
|
|
|
|
import io.mockk.Runs
|
|
import io.mockk.coEvery
|
|
import io.mockk.coVerify
|
|
import io.mockk.every
|
|
import io.mockk.just
|
|
import io.mockk.mockk
|
|
import io.mockk.spyk
|
|
import io.mockk.verify
|
|
import mozilla.components.lib.state.MiddlewareContext
|
|
import mozilla.components.service.glean.testing.GleanTestRule
|
|
import mozilla.components.support.test.robolectric.testContext
|
|
import mozilla.components.support.test.rule.MainCoroutineRule
|
|
import mozilla.components.support.test.rule.runTestOnMain
|
|
import org.junit.Assert.assertTrue
|
|
import org.junit.Before
|
|
import org.junit.Rule
|
|
import org.junit.Test
|
|
import org.junit.runner.RunWith
|
|
import org.mozilla.fenix.components.AppStore
|
|
import org.mozilla.fenix.components.appstate.AppAction
|
|
import org.mozilla.fenix.components.appstate.AppAction.MessagingAction.ConsumeMessageToShow
|
|
import org.mozilla.fenix.components.appstate.AppAction.MessagingAction.Evaluate
|
|
import org.mozilla.fenix.components.appstate.AppAction.MessagingAction.MessageClicked
|
|
import org.mozilla.fenix.components.appstate.AppAction.MessagingAction.MessageDismissed
|
|
import org.mozilla.fenix.components.appstate.AppAction.MessagingAction.Restore
|
|
import org.mozilla.fenix.components.appstate.AppAction.MessagingAction.UpdateMessageToShow
|
|
import org.mozilla.fenix.components.appstate.AppAction.MessagingAction.UpdateMessages
|
|
import org.mozilla.fenix.components.appstate.AppState
|
|
import org.mozilla.fenix.gleanplumb.Message
|
|
import org.mozilla.fenix.gleanplumb.MessagingState
|
|
import org.mozilla.fenix.gleanplumb.NimbusMessagingStorage
|
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
|
import org.mozilla.fenix.nimbus.MessageData
|
|
import org.mozilla.fenix.nimbus.StyleData
|
|
|
|
@RunWith(FenixRobolectricTestRunner::class)
|
|
class MessagingMiddlewareTest {
|
|
@get:Rule
|
|
val coroutinesTestRule = MainCoroutineRule()
|
|
private val coroutineScope = coroutinesTestRule.scope
|
|
private lateinit var store: AppStore
|
|
private lateinit var middleware: MessagingMiddleware
|
|
private lateinit var messagingStorage: NimbusMessagingStorage
|
|
private lateinit var middlewareContext: MiddlewareContext<AppState, AppAction>
|
|
|
|
@get:Rule
|
|
val gleanTestRule = GleanTestRule(testContext)
|
|
|
|
@Before
|
|
fun setUp() {
|
|
store = mockk(relaxed = true)
|
|
messagingStorage = mockk(relaxed = true)
|
|
middlewareContext = mockk(relaxed = true)
|
|
every { middlewareContext.store } returns store
|
|
|
|
middleware = MessagingMiddleware(
|
|
messagingStorage,
|
|
coroutineScope
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN Restore THEN get messages from the storage and UpdateMessages`() = runTestOnMain {
|
|
val messages: List<Message> = emptyList()
|
|
|
|
coEvery { messagingStorage.getMessages() } returns messages
|
|
|
|
middleware.invoke(middlewareContext, {}, Restore)
|
|
|
|
verify { store.dispatch(UpdateMessages(messages)) }
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN Restore THEN getNextMessage from the storage and UpdateMessageToShow`() = runTestOnMain {
|
|
val message: Message = mockk(relaxed = true)
|
|
val appState: AppState = mockk(relaxed = true)
|
|
val messagingState: MessagingState = mockk(relaxed = true)
|
|
|
|
every { messagingState.messages } returns emptyList()
|
|
every { appState.messaging } returns messagingState
|
|
every { middlewareContext.state } returns appState
|
|
every { messagingStorage.getNextMessage(any()) } returns message
|
|
|
|
middleware.invoke(middlewareContext, {}, Evaluate)
|
|
|
|
verify { middlewareContext.dispatch(UpdateMessageToShow(message)) }
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN MessageClicked THEN update storage`() = runTestOnMain {
|
|
val message = Message(
|
|
"control-id",
|
|
mockk(relaxed = true),
|
|
action = "action",
|
|
mockk(relaxed = true),
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id")
|
|
)
|
|
val appState: AppState = mockk(relaxed = true)
|
|
val messagingState: MessagingState = mockk(relaxed = true)
|
|
|
|
every { messagingState.messages } returns emptyList()
|
|
every { appState.messaging } returns messagingState
|
|
every { middlewareContext.state } returns appState
|
|
|
|
middleware.invoke(middlewareContext, {}, MessageClicked(message))
|
|
|
|
coVerify { messagingStorage.updateMetadata(message.metadata.copy(pressed = true)) }
|
|
verify { middlewareContext.dispatch(UpdateMessages(emptyList())) }
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN MessageDismissed THEN update storage`() = runTestOnMain {
|
|
val message = Message(
|
|
"control-id",
|
|
mockk(relaxed = true),
|
|
action = "action",
|
|
mockk(relaxed = true),
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id")
|
|
)
|
|
val appState: AppState = mockk(relaxed = true)
|
|
val messagingState: MessagingState = mockk(relaxed = true)
|
|
|
|
every { messagingState.messages } returns emptyList()
|
|
every { appState.messaging } returns messagingState
|
|
every { middlewareContext.state } returns appState
|
|
|
|
middleware.invoke(
|
|
middlewareContext, {},
|
|
MessageDismissed(message)
|
|
)
|
|
|
|
coVerify { messagingStorage.updateMetadata(message.metadata.copy(dismissed = true)) }
|
|
verify { middlewareContext.dispatch(UpdateMessages(emptyList())) }
|
|
}
|
|
|
|
@Test
|
|
fun `GIEN a expiring message WHEN MessageDisplayed THEN update storage`() = runTestOnMain {
|
|
val message = Message(
|
|
"control-id",
|
|
mockk(relaxed = true),
|
|
action = "action",
|
|
mockk(relaxed = true),
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id")
|
|
)
|
|
val appState: AppState = mockk(relaxed = true)
|
|
val messagingState: MessagingState = mockk(relaxed = true)
|
|
val spiedMiddleware = spyk(middleware)
|
|
|
|
every { spiedMiddleware.now() } returns 0L
|
|
every { messagingState.messages } returns emptyList()
|
|
every { appState.messaging } returns messagingState
|
|
every { middlewareContext.state } returns appState
|
|
|
|
spiedMiddleware.onMessagedDisplayed(message, middlewareContext)
|
|
|
|
coVerify { messagingStorage.updateMetadata(message.metadata.copy(displayCount = 1)) }
|
|
verify { middlewareContext.dispatch(UpdateMessages(emptyList())) }
|
|
verify { spiedMiddleware.sendExpiredMessageTelemetry(message.id) }
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN onMessageDismissed THEN updateMetadata,removeMessage , UpdateMessages and removeMessageToShowIfNeeded`() = runTestOnMain {
|
|
val message = Message(
|
|
"control-id",
|
|
mockk(relaxed = true),
|
|
action = "action",
|
|
mockk(relaxed = true),
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id")
|
|
)
|
|
|
|
val spiedMiddleware = spyk(middleware)
|
|
|
|
every { spiedMiddleware.removeMessage(middlewareContext, message) } returns emptyList()
|
|
every { spiedMiddleware.consumeMessageToShowIfNeeded(middlewareContext, message) } just Runs
|
|
|
|
spiedMiddleware.onMessageDismissed(middlewareContext, message)
|
|
|
|
coVerify { messagingStorage.updateMetadata(message.metadata.copy(dismissed = true)) }
|
|
verify { middlewareContext.dispatch(UpdateMessages(emptyList())) }
|
|
verify { spiedMiddleware.removeMessage(middlewareContext, message) }
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN removeMessage THEN remove the message`() = runTestOnMain {
|
|
val message = Message(
|
|
"control-id",
|
|
mockk(relaxed = true),
|
|
action = "action",
|
|
mockk(relaxed = true),
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id")
|
|
)
|
|
val messages = listOf(message)
|
|
val appState: AppState = mockk(relaxed = true)
|
|
val messagingState: MessagingState = mockk(relaxed = true)
|
|
|
|
every { messagingState.messages } returns messages
|
|
every { appState.messaging } returns messagingState
|
|
every { middlewareContext.state } returns appState
|
|
|
|
val results = middleware.removeMessage(middlewareContext, message)
|
|
|
|
assertTrue(results.isEmpty())
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN consumeMessageToShowIfNeeded THEN consume the message`() = runTestOnMain {
|
|
val message = Message(
|
|
"control-id",
|
|
mockk(relaxed = true),
|
|
action = "action",
|
|
mockk(relaxed = true),
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id")
|
|
)
|
|
val appState: AppState = mockk(relaxed = true)
|
|
val messagingState: MessagingState = mockk(relaxed = true)
|
|
|
|
every { messagingState.messageToShow } returns message
|
|
every { appState.messaging } returns messagingState
|
|
every { middlewareContext.state } returns appState
|
|
|
|
middleware.consumeMessageToShowIfNeeded(middlewareContext, message)
|
|
|
|
verify { middlewareContext.dispatch(ConsumeMessageToShow) }
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN updateMessage THEN update available messages`() = runTestOnMain {
|
|
val oldMessage = Message(
|
|
"oldMessage",
|
|
mockk(relaxed = true),
|
|
action = "action",
|
|
mockk(relaxed = true),
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id", pressed = false)
|
|
)
|
|
|
|
val updatedMessage = Message(
|
|
"oldMessage",
|
|
mockk(relaxed = true),
|
|
action = "action",
|
|
mockk(relaxed = true),
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id", pressed = true)
|
|
)
|
|
|
|
val spiedMiddleware = spyk(middleware)
|
|
|
|
val appState: AppState = mockk(relaxed = true)
|
|
val messagingState: MessagingState = mockk(relaxed = true)
|
|
|
|
every { messagingState.messageToShow } returns oldMessage
|
|
every { appState.messaging } returns messagingState
|
|
every { middlewareContext.state } returns appState
|
|
every { spiedMiddleware.removeMessage(middlewareContext, oldMessage) } returns emptyList()
|
|
|
|
val results = spiedMiddleware.updateMessage(middlewareContext, oldMessage, updatedMessage)
|
|
|
|
verify { middlewareContext.dispatch(UpdateMessageToShow(updatedMessage)) }
|
|
verify { spiedMiddleware.removeMessage(middlewareContext, oldMessage) }
|
|
|
|
assertTrue(results.size == 1)
|
|
assertTrue(results.first().metadata.pressed)
|
|
}
|
|
|
|
@Test
|
|
fun `GIVEN a message with that not surpassed the maxDisplayCount WHEN onMessagedDisplayed THEN update the available messages and the updateMetadata`() = runTestOnMain {
|
|
val style: StyleData = mockk(relaxed = true)
|
|
val oldMessageData: MessageData = mockk(relaxed = true)
|
|
val oldMessage = Message(
|
|
"oldMessage",
|
|
oldMessageData,
|
|
action = "action",
|
|
style,
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id", displayCount = 0)
|
|
)
|
|
val updatedMessage = oldMessage.copy(metadata = oldMessage.metadata.copy(displayCount = 1))
|
|
val spiedMiddleware = spyk(middleware)
|
|
|
|
every { spiedMiddleware.now() } returns 0
|
|
every { style.maxDisplayCount } returns 2
|
|
every {
|
|
spiedMiddleware.updateMessage(
|
|
middlewareContext,
|
|
oldMessage,
|
|
updatedMessage
|
|
)
|
|
} returns emptyList()
|
|
|
|
spiedMiddleware.onMessagedDisplayed(oldMessage, middlewareContext)
|
|
|
|
verify { spiedMiddleware.updateMessage(middlewareContext, oldMessage, updatedMessage) }
|
|
verify { middlewareContext.dispatch(UpdateMessages(emptyList())) }
|
|
coVerify { messagingStorage.updateMetadata(updatedMessage.metadata) }
|
|
}
|
|
|
|
@Test
|
|
fun `GIVEN a message with that surpassed the maxDisplayCount WHEN onMessagedDisplayed THEN remove the message and consume it`() = runTestOnMain {
|
|
val style: StyleData = mockk(relaxed = true)
|
|
val oldMessageData: MessageData = mockk(relaxed = true)
|
|
val oldMessage = Message(
|
|
"oldMessage",
|
|
oldMessageData,
|
|
action = "action",
|
|
style,
|
|
listOf("trigger"),
|
|
Message.Metadata("same-id", displayCount = 0)
|
|
)
|
|
val updatedMessage = oldMessage.copy(metadata = oldMessage.metadata.copy(displayCount = 1))
|
|
val spiedMiddleware = spyk(middleware)
|
|
|
|
every { spiedMiddleware.now() } returns 0
|
|
every { style.maxDisplayCount } returns 1
|
|
every {
|
|
spiedMiddleware.consumeMessageToShowIfNeeded(
|
|
middlewareContext,
|
|
oldMessage
|
|
)
|
|
} just Runs
|
|
every { spiedMiddleware.removeMessage(middlewareContext, oldMessage) } returns emptyList()
|
|
|
|
spiedMiddleware.onMessagedDisplayed(oldMessage, middlewareContext)
|
|
|
|
verify { spiedMiddleware.consumeMessageToShowIfNeeded(middlewareContext, oldMessage) }
|
|
verify { spiedMiddleware.removeMessage(middlewareContext, oldMessage) }
|
|
verify { middlewareContext.dispatch(UpdateMessages(emptyList())) }
|
|
coVerify { messagingStorage.updateMetadata(updatedMessage.metadata) }
|
|
verify { spiedMiddleware.sendShownMessageTelemetry(oldMessage.id) }
|
|
}
|
|
}
|