Skip to content

Commit 9149401

Browse files
committed
added unit test to guard against broken logic
1 parent 5e4be46 commit 9149401

File tree

5 files changed

+189
-44
lines changed

5 files changed

+189
-44
lines changed

thepeer-android/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ android {
1919
consumerProguardFiles "consumer-rules.pro"
2020
}
2121

22+
2223
buildFeatures {
2324
viewBinding true
2425
}

thepeer-android/src/main/java/co/thepeer/sdk/ui/fragments/HostDialogFragment.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,20 @@ class HostDialogFragment(private val thePeerParam: ThePeerParam) :
6060
}
6161

6262
activity?.let {
63-
binding.webViewPeer.addJavascriptInterface(WebInterface(it), "Android")
63+
binding.webViewPeer.addJavascriptInterface(WebInterface { results ->
64+
handleRedirect(results)
65+
}, "Android")
6466
}
6567

6668
binding.webViewPeer.loadUrl(transactionUrl)
6769
}
6870

71+
private fun handleRedirect(result: ThePeerResult) {
72+
val resultData = Intent()
73+
resultData.putExtra(ThePeerConstants.TRANSACTION_RESULT, result)
74+
activity?.setResult(AppCompatActivity.RESULT_OK, resultData)
75+
activity?.finish()
76+
}
6977
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
7078
val dialog = context?.let { BottomSheetDialog(it, R.style.CustomBottomSheetDialogTheme) }
7179
binding = FragmentHostDialogBinding.inflate(layoutInflater)

thepeer-android/src/main/java/co/thepeer/sdk/utils/WebInterface.kt

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,105 +12,103 @@ import com.google.gson.Gson
1212
/**
1313
* This webinterface handles events from the webview
1414
*/
15-
internal class WebInterface(private val activity: FragmentActivity) {
15+
internal class WebInterface(private val redirect: (ThePeerResult) -> Unit ) {
1616

1717

1818
private val SEND_INSUFFICIENT_FUNDS = "send.insufficient_funds"
1919
private val SEND_USER_INSUFFICIENT_FUNDS = "send.user_insufficient_funds"
20-
val SEND_SUCCESS = "send.success"
20+
private val SEND_SUCCESS = "send.success"
2121
private val DIRECT_CHARGE_INSUFFICIENT_FUNDS = "direct_debit.insufficient_funds"
2222
private val DIRECT_CHARGE_USER_INSUFFICIENT_FUNDS =
2323
"direct_debit.user_insufficient_funds"
24-
private val DIRECT_CHARGE_SUCCESS = "direct_debit.success"
24+
private val DIRECT_DEBIT_SUCCESS = "direct_debit.success"
2525
private val DIRECT_CHARGE_BUSINESS_DECLINE = "direct_debit.business_decline"
2626
private val DIRECT_CHARGE_USER_DECLINE = "direct_debit.user_decline"
2727
private val CHECKOUT_INSUFFICIENT_FUNDS = "checkout.insufficient_funds"
2828
private val CHECKOUT_USER_INSUFFICIENT_FUNDS = "checkout.user_insufficient_funds"
2929
private val CHECKOUT_SUCCESS = "checkout.success"
3030
private val CHECKOUT_BUSINESS_DECLINE = "checkout.business_decline"
3131
private val CHECKOUT_USER_DECLINE = "checkout.user_decline"
32-
private val SEND_CLOSE = "sed.close"
33-
private val DIRECT_CHARGE_CLOSE = "direct_debit.close"
32+
private val SEND_CLOSE = "send.close"
33+
private val DIRECT_DEBIT_CLOSE = "direct_debit.close"
3434
private val CHECKOUT_CLOSE = "checkout.close"
3535

3636

37-
private inline fun <reified T> convertToGsonFromString(json: String): T? =
38-
try{
39-
val adapter = Gson().getAdapter(T::class.java)
40-
adapter.fromJson(json)
41-
}catch (e: Exception){
42-
Log.e("WebInterface", e.message.toString())
43-
null
44-
}
37+
inline fun <reified T> convertToGsonFromString(json: String): T {
38+
val adapter = Gson().getAdapter(T::class.java)
39+
return adapter.fromJson(json)
40+
}
4541

4642

47-
private fun handleSendEvent(event: ThePeerEvent) {
43+
fun handleSendEvent(event: ThePeerEvent) {
4844
when (event.event) {
4945
SEND_SUCCESS -> {
50-
redirectWithResult(ThePeerResult.Success(event.data))
46+
redirect(ThePeerResult.Success(event.data))
5147
}
5248
SEND_CLOSE -> {
53-
redirectWithResult(ThePeerResult.Cancelled)
49+
redirect(ThePeerResult.Cancelled)
5450
}
5551
else -> {
56-
redirectWithResult(ThePeerResult.Error(Throwable(event.event.getLastPart())))
52+
redirect(ThePeerResult.Error(Throwable(event.event)))
5753
}
5854
}
5955

6056
}
6157

62-
private fun handleCheckoutEvent(event: ThePeerEvent) {
58+
fun handleCheckoutEvent(event: ThePeerEvent) {
6359
when (event.event) {
6460
CHECKOUT_SUCCESS -> {
65-
redirectWithResult(ThePeerResult.Success(event.data))
61+
redirect(ThePeerResult.Success(event.data))
6662
}
6763
CHECKOUT_CLOSE -> {
68-
redirectWithResult(ThePeerResult.Cancelled)
64+
redirect(ThePeerResult.Cancelled)
6965
}
7066
else -> {
71-
redirectWithResult(ThePeerResult.Error(Throwable(event.event.getLastPart())))
67+
redirect(ThePeerResult.Error(Throwable(event.event.getLastPart())))
7268
}
7369
}
7470

7571
}
7672

77-
private fun handleDirectChargeEvent(event: ThePeerEvent) {
73+
fun handleDirectDebitEvent(event: ThePeerEvent) {
7874

7975
when (event.event) {
80-
DIRECT_CHARGE_SUCCESS -> {
81-
redirectWithResult(ThePeerResult.Success(event.data))
76+
DIRECT_DEBIT_SUCCESS -> {
77+
redirect(ThePeerResult.Success(event.data))
8278
}
83-
DIRECT_CHARGE_CLOSE -> {
84-
redirectWithResult(ThePeerResult.Cancelled)
79+
DIRECT_DEBIT_CLOSE -> {
80+
redirect(ThePeerResult.Cancelled)
8581
}
8682
else -> {
87-
redirectWithResult(ThePeerResult.Error(Throwable(event.event.getLastPart())))
83+
redirect(ThePeerResult.Error(Throwable(event.event.getLastPart())))
8884
}
8985
}
9086

9187
}
9288

93-
private fun redirectWithResult(result: ThePeerResult) {
94-
val resultData = Intent()
95-
resultData.putExtra(ThePeerConstants.TRANSACTION_RESULT, result)
96-
activity.setResult(AppCompatActivity.RESULT_OK, resultData)
97-
activity.finish()
98-
}
89+
9990

10091
@JavascriptInterface
10192
fun sendResponse(response: String) {
10293
Logger.log(this, response)
103-
val event: ThePeerEvent? = convertToGsonFromString(response)
104-
when (event?.data?.channel) {
105-
"send" -> {
106-
handleSendEvent(event)
107-
}
108-
"checkout" -> {
109-
handleCheckoutEvent(event)
110-
}
111-
"direct_charge" -> {
112-
handleDirectChargeEvent(event)
94+
try {
95+
val event: ThePeerEvent = convertToGsonFromString(response)
96+
when (event.event.getFirstPart()) {
97+
"send" -> {
98+
handleSendEvent(event)
99+
}
100+
"checkout" -> {
101+
handleCheckoutEvent(event)
102+
}
103+
"direct_debit" -> {
104+
handleDirectDebitEvent(event)
105+
}
113106
}
107+
} catch (e: Exception) {
108+
Log.e("WebInterface", e.message.toString())
109+
114110
}
111+
112+
115113
}
116114
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package co.thepeer.sdk
2+
3+
object MockData {
4+
5+
6+
const val sendSuccess =
7+
"{\"event\":\"send.success\",\"data\":{\"id\":\"ea3a2ccb-ed0b-4bb6-8a7b-89a09a77cd62\",\"remark\":\"okk\",\"amount\":10000,\"charge\":0,\"refund\":false,\"type\":\"peer\",\"currency\":\"NGN\",\"status\":\"success\",\"mode\":\"debit\",\"meta\":{\"city\":\"Uyo\"},\"reference\":\"a5092442d5e3ddjjdjd\",\"checkout\":null,\"peer\":{\"business\":{\"name\":\"Cash App\",\"logo\":\"https://image.png\",\"logo_colour\":\"#77cc33\"},\"user\":{\"name\":\"user\",\"identifier\":\"sharp\",\"identifier_type\":\"username\"}},\"user\":{\"name\":\"user\",\"identifier\":\"doreen\",\"identifier_type\":\"username\",\"email\":\"[email protected]\",\"reference\":\"73f03de5-1043-4adhhfh\",\"created_at\":\"2021-04-19T19:50:26.000000Z\",\"updated_at\":\"2022-02-14T22:58:25.000000Z\"},\"channel\":\"send\",\"created_at\":\"2022-05-18T20:34:28.000000Z\",\"updated_at\":\"2022-05-18T20:34:28.000000Z\"}}"
8+
9+
const val sendClose = "{\"event\":\"send.close\"}"
10+
const val sendError = "{\"event\":\"send.user_insufficient_funds\"}"
11+
12+
const val checkoutSuccess =
13+
"{\"event\":\"checkout.success\",\"data\":{\"id\":\"ea3a2ccb-ed0b-4bb6-8a7b-89a09a77cd62\",\"remark\":\"okk\",\"amount\":10000,\"charge\":0,\"refund\":false,\"type\":\"peer\",\"currency\":\"NGN\",\"status\":\"success\",\"mode\":\"debit\",\"meta\":{\"city\":\"Uyo\"},\"reference\":\"a5092442d5e3ddjjdjd\",\"checkout\":null,\"peer\":{\"business\":{\"name\":\"Cash App\",\"logo\":\"https://image.png\",\"logo_colour\":\"#77cc33\"},\"user\":{\"name\":\"user\",\"identifier\":\"sharp\",\"identifier_type\":\"username\"}},\"user\":{\"name\":\"user\",\"identifier\":\"doreen\",\"identifier_type\":\"username\",\"email\":\"[email protected]\",\"reference\":\"73f03de5-1043-4adhhfh\",\"created_at\":\"2021-04-19T19:50:26.000000Z\",\"updated_at\":\"2022-02-14T22:58:25.000000Z\"},\"channel\":\"send\",\"created_at\":\"2022-05-18T20:34:28.000000Z\",\"updated_at\":\"2022-05-18T20:34:28.000000Z\"}}"
14+
15+
const val checkoutClose = "{\"event\":\"checkout.close\"}"
16+
17+
const val directDebitSuccess =
18+
"{\"event\":\"direct_debit.success\",\"data\":{\"id\":\"ea3a2ccb-ed0b-4bb6-8a7b-89a09a77cd62\",\"remark\":\"okk\",\"amount\":10000,\"charge\":0,\"refund\":false,\"type\":\"peer\",\"currency\":\"NGN\",\"status\":\"success\",\"mode\":\"debit\",\"meta\":{\"city\":\"Uyo\"},\"reference\":\"a5092442d5e3ddjjdjd\",\"checkout\":null,\"peer\":{\"business\":{\"name\":\"Cash App\",\"logo\":\"https://image.png\",\"logo_colour\":\"#77cc33\"},\"user\":{\"name\":\"user\",\"identifier\":\"sharp\",\"identifier_type\":\"username\"}},\"user\":{\"name\":\"user\",\"identifier\":\"doreen\",\"identifier_type\":\"username\",\"email\":\"[email protected]\",\"reference\":\"73f03de5-1043-4adhhfh\",\"created_at\":\"2021-04-19T19:50:26.000000Z\",\"updated_at\":\"2022-02-14T22:58:25.000000Z\"},\"channel\":\"send\",\"created_at\":\"2022-05-18T20:34:28.000000Z\",\"updated_at\":\"2022-05-18T20:34:28.000000Z\"}}"
19+
20+
const val directDebitClose = "{\"event\":\"direct_debit.close\"}"
21+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package co.thepeer.sdk
2+
3+
import android.content.Intent
4+
import android.util.Log
5+
import co.thepeer.sdk.model.ThePeerEvent
6+
import co.thepeer.sdk.model.ThePeerResult
7+
import co.thepeer.sdk.utils.Logger
8+
import co.thepeer.sdk.utils.ThePeerConstants
9+
import co.thepeer.sdk.utils.WebInterface
10+
import io.mockk.*
11+
import org.junit.Before
12+
import org.junit.Test
13+
import org.junit.Assert.assertEquals
14+
import org.junit.Ignore
15+
16+
17+
class WebInterfaceTest {
18+
19+
private lateinit var webInterface: WebInterface
20+
21+
@Before
22+
fun setup() {
23+
webInterface = WebInterface(mockk())
24+
mockkStatic(Log::class)
25+
mockk<Throwable>(relaxed = true)
26+
every { Log.d(any(), any()) } returns 0
27+
every { Log.e(any(), any()) } returns 0
28+
29+
30+
}
31+
32+
33+
@Test
34+
fun `handle send event - success`() {
35+
val event = webInterface.convertToGsonFromString(MockData.sendSuccess) as ThePeerEvent
36+
webInterface.sendResponse(MockData.sendSuccess)
37+
verify {
38+
webInterface.handleSendEvent(event)
39+
}
40+
41+
assertEquals("send.success", event.event)
42+
43+
}
44+
45+
@Test
46+
fun `handle send event - close`() {
47+
val event = webInterface.convertToGsonFromString(MockData.sendClose) as ThePeerEvent
48+
webInterface.sendResponse(MockData.sendClose)
49+
verify {
50+
webInterface.handleSendEvent(event)
51+
}
52+
53+
assertEquals("send.close", event.event)
54+
55+
}
56+
57+
@Test
58+
fun `handle send event - is error`() {
59+
val event = webInterface.convertToGsonFromString(MockData.sendError) as ThePeerEvent
60+
webInterface.sendResponse(MockData.sendError)
61+
verify {
62+
webInterface.handleSendEvent(event)
63+
}
64+
65+
assertEquals("send.user_insufficient_funds", event.event)
66+
67+
}
68+
69+
@Test
70+
fun `handle checkout event - success`() {
71+
val event = webInterface.convertToGsonFromString(MockData.checkoutSuccess) as ThePeerEvent
72+
webInterface.sendResponse(MockData.checkoutSuccess)
73+
verify {
74+
webInterface.handleCheckoutEvent(event)
75+
}
76+
77+
assertEquals("checkout.success", event.event)
78+
79+
}
80+
81+
@Test
82+
fun `handle checkout event - close`() {
83+
val event = webInterface.convertToGsonFromString(MockData.checkoutClose) as ThePeerEvent
84+
webInterface.sendResponse(MockData.checkoutClose)
85+
verify {
86+
webInterface.handleCheckoutEvent(event)
87+
}
88+
89+
assertEquals("checkout.close", event.event)
90+
91+
}
92+
93+
@Test
94+
fun `handle direct debit event - success`() {
95+
val event = webInterface.convertToGsonFromString(MockData.directDebitSuccess) as ThePeerEvent
96+
webInterface.sendResponse(MockData.directDebitSuccess)
97+
verify {
98+
webInterface.handleDirectDebitEvent(event)
99+
}
100+
101+
assertEquals("direct_debit.success", event.event)
102+
103+
}
104+
105+
@Test
106+
fun `handle direct debit event - close`() {
107+
val event = webInterface.convertToGsonFromString(MockData.directDebitClose) as ThePeerEvent
108+
webInterface.sendResponse(MockData.directDebitClose)
109+
verify {
110+
webInterface.handleDirectDebitEvent(event)
111+
}
112+
113+
assertEquals("direct_debit.close", event.event)
114+
115+
}
116+
117+
}

0 commit comments

Comments
 (0)