Skip to content

Commit

Permalink
Merge pull request #2244 from wordpress-mobile/issue/15749-msd-stats-…
Browse files Browse the repository at this point in the history
…card-handle-success-response

 MSD - Stats Card - Handle Success Response
  • Loading branch information
ashiagr authored Feb 18, 2022
2 parents dd9c87b + 83c50fd commit 3159174
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import org.mockito.junit.MockitoJUnitRunner
import org.wordpress.android.fluxc.Dispatcher
import org.wordpress.android.fluxc.UnitTestUtils
import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.fluxc.model.dashboard.CardModel
import org.wordpress.android.fluxc.network.BaseRequest.BaseNetworkError
import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType
import org.wordpress.android.fluxc.network.UserAgent
Expand All @@ -31,6 +32,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient.CardsResponse
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient.PostResponse
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient.PostsResponse
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient.TodaysStatsResponse
import org.wordpress.android.fluxc.store.dashboard.CardsStore.CardsErrorType
import org.wordpress.android.fluxc.store.dashboard.CardsStore.CardsPayload
import org.wordpress.android.fluxc.test
Expand All @@ -39,8 +41,19 @@ import org.wordpress.android.fluxc.test

private const val DATE_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss"

/* CARD TYPES */

private val CARD_TYPES = listOf(CardModel.Type.TODAYS_STATS, CardModel.Type.POSTS)

/* RESPONSE */

private val TODAYS_STATS_RESPONSE = TodaysStatsResponse(
views = 100,
visitors = 30,
likes = 50,
comments = 10
)

private val DRAFT_POST_RESPONSE_TWO = PostResponse(
id = 708,
title = "",
Expand Down Expand Up @@ -77,6 +90,7 @@ private val POSTS_RESPONSE = PostsResponse(
)

private val CARDS_RESPONSE = CardsResponse(
todaysStats = TODAYS_STATS_RESPONSE,
posts = POSTS_RESPONSE
)

Expand All @@ -90,13 +104,15 @@ class CardsRestClientTest {
@Mock private lateinit var site: SiteModel

private lateinit var urlCaptor: KArgumentCaptor<String>
private lateinit var paramsCaptor: KArgumentCaptor<Map<String, String>>
private lateinit var restClient: CardsRestClient

private val siteId: Long = 1

@Before
fun setUp() {
urlCaptor = argumentCaptor()
paramsCaptor = argumentCaptor()
restClient = CardsRestClient(
wpComGsonRequestBuilder,
dispatcher,
Expand All @@ -112,7 +128,7 @@ class CardsRestClientTest {
val json = UnitTestUtils.getStringFromResourceFile(javaClass, DASHBOARD_CARDS_JSON)
initFetchCards(data = getCardsResponseFromJsonString(json))

restClient.fetchCards(site)
restClient.fetchCards(site, CARD_TYPES)

assertEquals(urlCaptor.firstValue, "$API_SITE_PATH/${site.siteId}/$API_DASHBOARD_CARDS_PATH")
}
Expand All @@ -122,7 +138,7 @@ class CardsRestClientTest {
val json = UnitTestUtils.getStringFromResourceFile(javaClass, DASHBOARD_CARDS_JSON)
initFetchCards(data = getCardsResponseFromJsonString(json))

val result = restClient.fetchCards(site)
val result = restClient.fetchCards(site, CARD_TYPES)

assertSuccess(CARDS_RESPONSE, result)
}
Expand All @@ -131,7 +147,7 @@ class CardsRestClientTest {
fun `given timeout, when fetch cards gets triggered, then return cards timeout error`() = test {
initFetchCards(error = WPComGsonNetworkError(BaseNetworkError(GenericErrorType.TIMEOUT)))

val result = restClient.fetchCards(site)
val result = restClient.fetchCards(site, CARD_TYPES)

assertError(CardsErrorType.TIMEOUT, result)
}
Expand All @@ -140,7 +156,7 @@ class CardsRestClientTest {
fun `given network error, when fetch cards gets triggered, then return cards api error`() = test {
initFetchCards(error = WPComGsonNetworkError(BaseNetworkError(GenericErrorType.NETWORK_ERROR)))

val result = restClient.fetchCards(site)
val result = restClient.fetchCards(site, CARD_TYPES)

assertError(CardsErrorType.API_ERROR, result)
}
Expand All @@ -149,7 +165,7 @@ class CardsRestClientTest {
fun `given invalid response, when fetch cards gets triggered, then return cards invalid response error`() = test {
initFetchCards(error = WPComGsonNetworkError(BaseNetworkError(GenericErrorType.INVALID_RESPONSE)))

val result = restClient.fetchCards(site)
val result = restClient.fetchCards(site, CARD_TYPES)

assertError(CardsErrorType.INVALID_RESPONSE, result)
}
Expand All @@ -158,7 +174,7 @@ class CardsRestClientTest {
fun `given not authenticated, when fetch cards gets triggered, then return cards auth required error`() = test {
initFetchCards(error = WPComGsonNetworkError(BaseNetworkError(GenericErrorType.NOT_AUTHENTICATED)))

val result = restClient.fetchCards(site)
val result = restClient.fetchCards(site, CARD_TYPES)

assertError(CardsErrorType.AUTHORIZATION_REQUIRED, result)
}
Expand All @@ -167,7 +183,7 @@ class CardsRestClientTest {
fun `given unknown error, when fetch cards gets triggered, then return cards generic error`() = test {
initFetchCards(error = WPComGsonNetworkError(BaseNetworkError(GenericErrorType.UNKNOWN)))

val result = restClient.fetchCards(site)
val result = restClient.fetchCards(site, CARD_TYPES)

assertError(CardsErrorType.GENERIC_ERROR, result)
}
Expand All @@ -188,7 +204,7 @@ class CardsRestClientTest {
wpComGsonRequestBuilder.syncGetRequest(
eq(restClient),
urlCaptor.capture(),
eq(mapOf()),
paramsCaptor.capture(),
eq(CardsResponse::class.java),
eq(false),
any(),
Expand Down Expand Up @@ -226,7 +242,7 @@ class CardsRestClientTest {
companion object {
private const val API_BASE_PATH = "https://public-api.wordpress.com/wpcom/v2"
private const val API_SITE_PATH = "$API_BASE_PATH/sites"
private const val API_DASHBOARD_CARDS_PATH = "dashboard/cards/"
private const val API_DASHBOARD_CARDS_PATH = "dashboard/cards-data/"

private const val DASHBOARD_CARDS_JSON = "wp/dashboard/cards.json"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.fluxc.model.dashboard.CardModel
import org.wordpress.android.fluxc.model.dashboard.CardModel.PostsCardModel
import org.wordpress.android.fluxc.model.dashboard.CardModel.PostsCardModel.PostCardModel
import org.wordpress.android.fluxc.model.dashboard.CardModel.TodaysStatsCardModel
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient.CardsResponse
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient.PostResponse
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient.PostsResponse
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsRestClient.TodaysStatsResponse
import org.wordpress.android.fluxc.network.rest.wpcom.dashboard.CardsUtils
import org.wordpress.android.fluxc.persistence.dashboard.CardsDao
import org.wordpress.android.fluxc.persistence.dashboard.CardsDao.CardEntity
Expand All @@ -34,6 +36,13 @@ import kotlin.test.assertNull

const val SITE_LOCAL_ID = 1

/* TODAY'S STATS */

const val TODAYS_STATS_VIEWS = 100
const val TODAYS_STATS_VISITORS = 30
const val TODAYS_STATS_LIKES = 50
const val TODAYS_STATS_COMMENTS = 10

/* POST */

const val POST_ID = 1
Expand All @@ -42,8 +51,19 @@ const val POST_CONTENT = "content"
const val POST_FEATURED_IMAGE = "featuredImage"
const val POST_DATE = "2021-12-27 11:33:55"

/* CARD TYPES */

private val CARD_TYPES = listOf(CardModel.Type.TODAYS_STATS, CardModel.Type.POSTS)

/* RESPONSE */

private val TODAYS_STATS_RESPONSE = TodaysStatsResponse(
views = TODAYS_STATS_VIEWS,
visitors = TODAYS_STATS_VISITORS,
likes = TODAYS_STATS_LIKES,
comments = TODAYS_STATS_COMMENTS
)

private val POST_RESPONSE = PostResponse(
id = POST_ID,
title = POST_TITLE,
Expand All @@ -59,10 +79,17 @@ private val POSTS_RESPONSE = PostsResponse(
)

private val CARDS_RESPONSE = CardsResponse(
todaysStats = TODAYS_STATS_RESPONSE,
posts = POSTS_RESPONSE
)

/* MODEL */
private val TODAYS_STATS_MODEL = TodaysStatsCardModel(
views = TODAYS_STATS_VIEWS,
visitors = TODAYS_STATS_VISITORS,
likes = TODAYS_STATS_LIKES,
comments = TODAYS_STATS_COMMENTS
)

private val POST_MODEL = PostCardModel(
id = POST_ID,
Expand All @@ -79,10 +106,17 @@ private val POSTS_MODEL = PostsCardModel(
)

private val CARDS_MODEL = listOf(
TODAYS_STATS_MODEL,
POSTS_MODEL
)

/* ENTITY */
private val TODAYS_STATS_ENTITY = CardEntity(
siteLocalId = SITE_LOCAL_ID,
type = CardModel.Type.TODAYS_STATS.name,
date = CardsUtils.getInsertDate(),
json = CardsUtils.GSON.toJson(TODAYS_STATS_MODEL)
)

private val POSTS_ENTITY = CardEntity(
siteLocalId = SITE_LOCAL_ID,
Expand All @@ -92,6 +126,7 @@ private val POSTS_ENTITY = CardEntity(
)

private val CARDS_ENTITY = listOf(
TODAYS_STATS_ENTITY,
POSTS_ENTITY
)

Expand All @@ -118,21 +153,41 @@ class CardsStoreTest {
}

@Test
fun `given cards response, when fetch cards gets triggered, then cards model is inserted into db`() = test {
fun `given all card types, when fetch cards triggered, then all cards model is inserted into db`() = test {
val payload = CardsPayload(CARDS_RESPONSE)
whenever(restClient.fetchCards(siteModel)).thenReturn(payload)
whenever(restClient.fetchCards(siteModel, CARD_TYPES)).thenReturn(payload)

cardsStore.fetchCards(siteModel)
cardsStore.fetchCards(siteModel, CARD_TYPES)

verify(dao).insertWithDate(siteModel.id, CARDS_MODEL)
}

@Test
fun `given todays stats type, when fetch cards triggered, then today's stats card model inserted into db`() = test {
val payload = CardsPayload(CardsResponse(todaysStats = TODAYS_STATS_RESPONSE))
whenever(restClient.fetchCards(siteModel, listOf(CardModel.Type.TODAYS_STATS))).thenReturn(payload)

cardsStore.fetchCards(siteModel, listOf(CardModel.Type.TODAYS_STATS))

verify(dao).insertWithDate(siteModel.id, listOf(TODAYS_STATS_MODEL))
}

@Test
fun `given posts type, when fetch cards triggered, then post card model inserted into db`() = test {
val payload = CardsPayload(CardsResponse(posts = POSTS_RESPONSE))
whenever(restClient.fetchCards(siteModel, listOf(CardModel.Type.POSTS))).thenReturn(payload)

cardsStore.fetchCards(siteModel, listOf(CardModel.Type.POSTS))

verify(dao).insertWithDate(siteModel.id, listOf(POSTS_MODEL))
}

@Test
fun `given cards response, when fetch cards gets triggered, then empty cards model is returned`() = test {
val payload = CardsPayload(CARDS_RESPONSE)
whenever(restClient.fetchCards(siteModel)).thenReturn(payload)
whenever(restClient.fetchCards(siteModel, CARD_TYPES)).thenReturn(payload)

val result = cardsStore.fetchCards(siteModel)
val result = cardsStore.fetchCards(siteModel, CARD_TYPES)

assertThat(result.model).isNull()
assertThat(result.error).isNull()
Expand All @@ -141,10 +196,10 @@ class CardsStoreTest {
@Test
fun `given card response with exception, when fetch cards gets triggered, then cards error is returned`() = test {
val payload = CardsPayload(CARDS_RESPONSE)
whenever(restClient.fetchCards(siteModel)).thenReturn(payload)
whenever(restClient.fetchCards(siteModel, CARD_TYPES)).thenReturn(payload)
whenever(dao.insertWithDate(siteModel.id, CARDS_MODEL)).thenThrow(IllegalStateException("Error"))

val result = cardsStore.fetchCards(siteModel)
val result = cardsStore.fetchCards(siteModel, CARD_TYPES)

assertThat(result.model).isNull()
assertEquals(CardsErrorType.GENERIC_ERROR, result.error.type)
Expand All @@ -155,9 +210,9 @@ class CardsStoreTest {
fun `given cards error, when fetch cards gets triggered, then cards error is returned`() = test {
val errorType = CardsErrorType.API_ERROR
val payload = CardsPayload<CardsResponse>(CardsError(errorType))
whenever(restClient.fetchCards(siteModel)).thenReturn(payload)
whenever(restClient.fetchCards(siteModel, CARD_TYPES)).thenReturn(payload)

val result = cardsStore.fetchCards(siteModel)
val result = cardsStore.fetchCards(siteModel, CARD_TYPES)

assertThat(result.model).isNull()
assertEquals(errorType, result.error.type)
Expand All @@ -168,9 +223,9 @@ class CardsStoreTest {
fun `given authorization required, when fetch cards gets triggered, then db is cleared of cards model`() = test {
val errorType = CardsErrorType.AUTHORIZATION_REQUIRED
val payload = CardsPayload<CardsResponse>(CardsError(errorType))
whenever(restClient.fetchCards(siteModel)).thenReturn(payload)
whenever(restClient.fetchCards(siteModel, CARD_TYPES)).thenReturn(payload)

cardsStore.fetchCards(siteModel)
cardsStore.fetchCards(siteModel, CARD_TYPES)

verify(dao).clear()
}
Expand All @@ -179,9 +234,9 @@ class CardsStoreTest {
fun `given authorization required, when fetch cards gets triggered, then empty cards model is returned`() = test {
val errorType = CardsErrorType.AUTHORIZATION_REQUIRED
val payload = CardsPayload<CardsResponse>(CardsError(errorType))
whenever(restClient.fetchCards(siteModel)).thenReturn(payload)
whenever(restClient.fetchCards(siteModel, CARD_TYPES)).thenReturn(payload)

val result = cardsStore.fetchCards(siteModel)
val result = cardsStore.fetchCards(siteModel, CARD_TYPES)

assertThat(result.model).isNull()
assertThat(result.error).isNull()
Expand All @@ -190,9 +245,9 @@ class CardsStoreTest {
@Test
fun `given empty cards payload, when fetch cards gets triggered, then cards error is returned`() = test {
val payload = CardsPayload<CardsResponse>()
whenever(restClient.fetchCards(siteModel)).thenReturn(payload)
whenever(restClient.fetchCards(siteModel, CARD_TYPES)).thenReturn(payload)

val result = cardsStore.fetchCards(siteModel)
val result = cardsStore.fetchCards(siteModel, CARD_TYPES)

assertThat(result.model).isNull()
assertEquals(CardsErrorType.INVALID_RESPONSE, result.error.type)
Expand All @@ -201,10 +256,30 @@ class CardsStoreTest {

@Test
fun `when get cards gets triggered, then a flow of cards model is returned`() = test {
whenever(dao.get(SITE_LOCAL_ID)).thenReturn(flowOf(CARDS_ENTITY))
whenever(dao.get(SITE_LOCAL_ID, CARD_TYPES)).thenReturn(flowOf(CARDS_ENTITY))

val result = cardsStore.getCards(siteModel).single()
val result = cardsStore.getCards(siteModel, CARD_TYPES).single()

assertThat(result).isEqualTo(CardsResult(CARDS_MODEL))
}

@Test
fun `when get cards gets triggered for today's stats only, then a flow of today's stats card model is returned`() =
test {
whenever(dao.get(SITE_LOCAL_ID, listOf(CardModel.Type.TODAYS_STATS)))
.thenReturn(flowOf(listOf(TODAYS_STATS_ENTITY)))

val result = cardsStore.getCards(siteModel, listOf(CardModel.Type.TODAYS_STATS)).single()

assertThat(result).isEqualTo(CardsResult(listOf(TODAYS_STATS_MODEL)))
}

@Test
fun `when get cards gets triggered for posts only, then a flow of post card model is returned`() = test {
whenever(dao.get(SITE_LOCAL_ID, listOf(CardModel.Type.POSTS))).thenReturn(flowOf(listOf(POSTS_ENTITY)))

val result = cardsStore.getCards(siteModel, listOf(CardModel.Type.POSTS)).single()

assertThat(result).isEqualTo(CardsResult(listOf(POSTS_MODEL)))
}
}
6 changes: 6 additions & 0 deletions example/src/test/resources/wp/dashboard/cards.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
{
"todays_stats": {
"views": 100,
"visitors": 30,
"likes": 50,
"comments": 10
},
"posts": {
"has_published": true,
"draft": [
Expand Down
2 changes: 1 addition & 1 deletion fluxc-processor/src/main/resources/wp-com-v2-endpoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

/read/sites/$site#String/notification-subscriptions/$action#String

/sites/$site/dashboard/cards
/sites/$site/dashboard/cards-data

/sites/$site/activity
/sites/$site/activity/count/group
Expand Down
Loading

0 comments on commit 3159174

Please sign in to comment.