@@ -5,13 +5,15 @@ import com.woocommerce.android.tools.SelectedSite
55import com.woocommerce.android.ui.orders.OrderTestUtils
66import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule
77import kotlinx.coroutines.ExperimentalCoroutinesApi
8+ import kotlinx.coroutines.flow.toList
89import kotlinx.coroutines.test.runTest
910import org.assertj.core.api.Assertions.assertThat
1011import org.junit.Rule
1112import org.mockito.kotlin.any
1213import org.mockito.kotlin.anyOrNull
1314import org.mockito.kotlin.eq
1415import org.mockito.kotlin.mock
16+ import org.mockito.kotlin.never
1517import org.mockito.kotlin.verify
1618import org.mockito.kotlin.whenever
1719import org.wordpress.android.fluxc.model.LocalOrRemoteId
@@ -33,25 +35,35 @@ class WooPosOrdersDataSourceTest {
3335 private val siteModel: SiteModel = mock()
3436 private val selectedSite: SelectedSite = mock { on { get() }.thenReturn(siteModel) }
3537 private val orderMapper: OrderMapper = mock()
38+ private val ordersCache: WooPosOrdersInMemoryCache = mock()
3639
3740 private val sut = WooPosOrdersDataSource (
3841 restClient = orderRestClient,
3942 selectedSite = selectedSite,
40- orderMapper = orderMapper
43+ orderMapper = orderMapper,
44+ ordersCache = ordersCache
4145 )
4246
4347 @Test
44- fun `given rest client returns entities , when loadOrders called , then should map them to app models ` () = runTest {
48+ fun `given cache and successful fetch , when loadOrders collected , then emits cache first then mapped network and stores in cache ` () = runTest {
4549 // GIVEN
50+ val cachedOrder = OrderTestUtils .generateTestOrder()
51+ whenever(ordersCache.getAll()).thenReturn(listOf (cachedOrder))
52+
53+ // Network returns two entities
4654 val e1 = OrderEntity (localSiteId = LocalOrRemoteId .LocalId (1 ), 1 )
4755 val e2 = OrderEntity (localSiteId = LocalOrRemoteId .LocalId (1 ), 2 )
4856 val entities = listOf (
4957 e1 to emptyList<WCMetaData >(),
5058 e2 to emptyList<WCMetaData >()
5159 )
60+
5261 val firstOrder = OrderTestUtils .generateTestOrder()
5362 val secondOrder = OrderTestUtils .generateTestOrder()
5463
64+ whenever(orderMapper.toAppModel(e1)).thenReturn(firstOrder)
65+ whenever(orderMapper.toAppModel(e2)).thenReturn(secondOrder)
66+
5567 val payload = WCOrderStore .FetchOrdersResponsePayload (
5668 site = siteModel,
5769 ordersWithMeta = entities
@@ -69,18 +81,24 @@ class WooPosOrdersDataSourceTest {
6981 )
7082 ).thenReturn(payload)
7183
72- whenever(orderMapper.toAppModel(e1)).thenReturn(firstOrder)
73- whenever(orderMapper.toAppModel(e2)).thenReturn(secondOrder)
74-
7584 // WHEN
76- val result = sut.loadOrders()
85+ val emissions = sut.loadOrders().toList( mutableListOf () )
7786
7887 // THEN
79- assertThat(result).isInstanceOf(LoadOrdersResult .Success ::class .java)
80- val success = result as LoadOrdersResult .Success
81- assertThat(success.orders).containsExactly(firstOrder, secondOrder)
88+ assertThat(emissions).hasSize(2 )
89+ // First emission = cache
90+ val first = emissions[0 ]
91+ assertThat(first).isInstanceOf(LoadOrdersResult .Success ::class .java)
92+ assertThat((first as LoadOrdersResult .Success ).orders).containsExactly(cachedOrder)
93+
94+ // Second emission = network mapped
95+ val second = emissions[1 ]
96+ assertThat(second).isInstanceOf(LoadOrdersResult .Success ::class .java)
97+ assertThat((second as LoadOrdersResult .Success ).orders).containsExactly(firstOrder, secondOrder)
8298
8399 verify(selectedSite).get()
100+ verify(ordersCache).getAll()
101+ verify(ordersCache).setAll(listOf (firstOrder, secondOrder))
84102 verify(orderRestClient).fetchOrders(
85103 site = eq(siteModel),
86104 count = eq(25 ),
@@ -93,8 +111,11 @@ class WooPosOrdersDataSourceTest {
93111 }
94112
95113 @Test
96- fun `given store returns error, when loadOrders called , then should return error result ` () = runTest {
114+ fun `given cache and fetch error, when loadOrders collected , then emits cache then error without caching ` () = runTest {
97115 // GIVEN
116+ val cachedOrder = OrderTestUtils .generateTestOrder()
117+ whenever(ordersCache.getAll()).thenReturn(listOf (cachedOrder))
118+
98119 val orderError = WCOrderStore .OrderError (
99120 type = WCOrderStore .OrderErrorType .GENERIC_ERROR ,
100121 message = " generic error"
@@ -118,13 +139,21 @@ class WooPosOrdersDataSourceTest {
118139 ).thenReturn(payload)
119140
120141 // WHEN
121- val result = sut.loadOrders()
142+ val emissions = sut.loadOrders().toList( mutableListOf () )
122143
123144 // THEN
124- assertThat(result).isInstanceOf(LoadOrdersResult .Error ::class .java)
125- val error = result as LoadOrdersResult .Error
126- assertThat(error.message).isEqualTo(orderError.message)
145+ assertThat(emissions).hasSize(2 )
146+
147+ val first = emissions[0 ]
148+ assertThat(first).isInstanceOf(LoadOrdersResult .Success ::class .java)
149+ assertThat((first as LoadOrdersResult .Success ).orders).containsExactly(cachedOrder)
150+
151+ val second = emissions[1 ]
152+ assertThat(second).isInstanceOf(LoadOrdersResult .Error ::class .java)
153+ assertThat((second as LoadOrdersResult .Error ).message).isEqualTo(" generic error" )
127154
155+ verify(ordersCache).getAll()
156+ verify(ordersCache, never()).setAll(any())
128157 verify(orderRestClient).fetchOrders(
129158 site = eq(siteModel),
130159 count = eq(25 ),
@@ -137,13 +166,14 @@ class WooPosOrdersDataSourceTest {
137166 }
138167
139168 @Test
140- fun `given default site and pagination , when loadOrders called , then should forward params including createdVia` () = runTest {
169+ fun `given empty cache , when loadOrders collected , then forwards params including createdVia and emits empty then empty ` () = runTest {
141170 // GIVEN
171+ whenever(ordersCache.getAll()).thenReturn(emptyList())
172+
142173 val payload = WCOrderStore .FetchOrdersResponsePayload (
143174 site = siteModel,
144175 ordersWithMeta = emptyList()
145176 )
146-
147177 whenever(
148178 orderRestClient.fetchOrders(
149179 site = eq(siteModel),
@@ -157,14 +187,22 @@ class WooPosOrdersDataSourceTest {
157187 ).thenReturn(payload)
158188
159189 // WHEN
160- val result = sut.loadOrders()
190+ val emissions = sut.loadOrders().toList( mutableListOf () )
161191
162192 // THEN
163- assertThat(result).isInstanceOf(LoadOrdersResult .Success ::class .java)
164- val success = result as LoadOrdersResult .Success
165- assertThat(success.orders).isEmpty()
193+ assertThat(emissions).hasSize(2 )
194+
195+ val first = emissions[0 ]
196+ assertThat(first).isInstanceOf(LoadOrdersResult .Success ::class .java)
197+ assertThat((first as LoadOrdersResult .Success ).orders).isEmpty()
198+
199+ val second = emissions[1 ]
200+ assertThat(second).isInstanceOf(LoadOrdersResult .Success ::class .java)
201+ assertThat((second as LoadOrdersResult .Success ).orders).isEmpty()
166202
167203 verify(selectedSite).get()
204+ verify(ordersCache).getAll()
205+ verify(ordersCache).setAll(emptyList())
168206 verify(orderRestClient).fetchOrders(
169207 site = eq(siteModel),
170208 count = eq(25 ),
0 commit comments