2222 */
2323package com.shopify.checkoutsheetkit
2424
25+ import android.Manifest
26+ import android.content.Context
2527import android.content.Intent
28+ import android.content.pm.PackageInfo
2629import android.content.pm.PackageManager
2730import android.content.pm.ResolveInfo
2831import android.net.Uri
@@ -34,10 +37,9 @@ import org.assertj.core.api.Assertions.assertThat
3437import org.junit.Before
3538import org.junit.Test
3639import org.junit.runner.RunWith
37- import org.mockito.kotlin.any
38- import org.mockito.kotlin.mock
39- import org.mockito.kotlin.times
40- import org.mockito.kotlin.verify
40+ import org.mockito.Mockito.`when`
41+ import org.mockito.MockitoAnnotations
42+ import org.mockito.kotlin.*
4143import org.robolectric.Robolectric
4244import org.robolectric.RobolectricTestRunner
4345import org.robolectric.RuntimeEnvironment
@@ -47,14 +49,22 @@ import org.robolectric.shadows.ShadowActivity
4749@RunWith(RobolectricTestRunner ::class )
4850class DefaultCheckoutEventProcessorTest {
4951
52+ private lateinit var context: Context
5053 private lateinit var activity: ComponentActivity
5154 private lateinit var shadowActivity: ShadowActivity
5255 private val mockCallback = mock<GeolocationPermissions .Callback >()
56+ private lateinit var processor: TestCheckoutEventProcessor
57+ private lateinit var packageManager: PackageManager
5358
5459 @Before
5560 fun setUp () {
61+ MockitoAnnotations .openMocks(this )
5662 activity = Robolectric .buildActivity(ComponentActivity ::class .java).get()
5763 shadowActivity = shadowOf(activity)
64+ context = mock()
65+ packageManager = mock()
66+ `when `(context.packageManager).thenReturn(packageManager)
67+ processor = TestCheckoutEventProcessor (context)
5868 }
5969
6070 @Test
@@ -77,7 +87,8 @@ class DefaultCheckoutEventProcessorTest {
7787 processor.onCheckoutLinkClicked(uri)
7888
7989 val intent = shadowActivity.peekNextStartedActivityForResult().intent
80- assertThat(intent.getStringArrayExtra(Intent .EXTRA_EMAIL )).isEqualTo(arrayOf(" test.user@shopify.com" ))
90+ assertThat(intent.getStringArrayExtra(Intent .EXTRA_EMAIL ))
91+ .isEqualTo(arrayOf(" test.user@shopify.com" ))
8192 assertThat(intent.action).isEqualTo(" android.intent.action.SEND" )
8293 }
8394
@@ -105,12 +116,23 @@ class DefaultCheckoutEventProcessorTest {
105116 val shadowPackageManager = shadowOf(pm)
106117 shadowPackageManager.addResolveInfoForIntent(expectedIntent, ResolveInfo ())
107118
108- val processor = object : DefaultCheckoutEventProcessor (activity, log) {
109- override fun onCheckoutCompleted (checkoutCompletedEvent : CheckoutCompletedEvent ) {/* not implemented */ }
110- override fun onCheckoutFailed (error : CheckoutException ) {/* not implemented */ }
111- override fun onCheckoutCanceled () {/* not implemented */ }
112- override fun onWebPixelEvent (event : PixelEvent ) {/* not implemented */ }
113- }
119+ val processor =
120+ object : DefaultCheckoutEventProcessor (activity, log) {
121+ override fun onCheckoutCompleted (
122+ checkoutCompletedEvent : CheckoutCompletedEvent
123+ ) {
124+ /* not implemented */
125+ }
126+ override fun onCheckoutFailed (error : CheckoutException ) {
127+ /* not implemented */
128+ }
129+ override fun onCheckoutCanceled () {
130+ /* not implemented */
131+ }
132+ override fun onWebPixelEvent (event : PixelEvent ) {
133+ /* not implemented */
134+ }
135+ }
114136
115137 processor.onCheckoutLinkClicked(uri)
116138
@@ -122,19 +144,34 @@ class DefaultCheckoutEventProcessorTest {
122144 @Test
123145 fun `onCheckoutLinkedClick with unhandled scheme logs warning` () {
124146 val log = mock<LogWrapper >()
125- val processor = object : DefaultCheckoutEventProcessor (activity, log) {
126- override fun onCheckoutCompleted (checkoutCompletedEvent : CheckoutCompletedEvent ) {/* not implemented */ }
127- override fun onCheckoutFailed (error : CheckoutException ) {/* not implemented */ }
128- override fun onCheckoutCanceled () {/* not implemented */ }
129- override fun onWebPixelEvent (event : PixelEvent ) {/* not implemented */ }
130- }
147+ val processor =
148+ object : DefaultCheckoutEventProcessor (activity, log) {
149+ override fun onCheckoutCompleted (
150+ checkoutCompletedEvent : CheckoutCompletedEvent
151+ ) {
152+ /* not implemented */
153+ }
154+ override fun onCheckoutFailed (error : CheckoutException ) {
155+ /* not implemented */
156+ }
157+ override fun onCheckoutCanceled () {
158+ /* not implemented */
159+ }
160+ override fun onWebPixelEvent (event : PixelEvent ) {
161+ /* not implemented */
162+ }
163+ }
131164
132165 val uri = Uri .parse(" ftp:random" )
133166
134167 processor.onCheckoutLinkClicked(uri)
135168
136169 assertThat(shadowActivity.peekNextStartedActivityForResult()).isNull()
137- verify(log).w(" DefaultCheckoutEventProcessor" , " Unrecognized scheme for link clicked in checkout 'ftp:random'" )
170+ verify(log)
171+ .w(
172+ " DefaultCheckoutEventProcessor" ,
173+ " Unrecognized scheme for link clicked in checkout 'ftp:random'"
174+ )
138175 }
139176
140177 @Test
@@ -144,7 +181,9 @@ class DefaultCheckoutEventProcessorTest {
144181 var recoverable: Boolean? = null
145182 val processor =
146183 object : DefaultCheckoutEventProcessor (activity, log) {
147- override fun onCheckoutCompleted (checkoutCompletedEvent : CheckoutCompletedEvent ) {
184+ override fun onCheckoutCompleted (
185+ checkoutCompletedEvent : CheckoutCompletedEvent
186+ ) {
148187 /* not implemented */
149188 }
150189 override fun onCheckoutFailed (error : CheckoutException ) {
@@ -169,35 +208,77 @@ class DefaultCheckoutEventProcessorTest {
169208 }
170209
171210 @Test
172- fun `onGeolocationPermissionsShowPrompt should invoke callback with correct args` () {
173- val origin = " http://shopify.com"
174- val processor = object : DefaultCheckoutEventProcessor (mock(), mock()) {
175- override fun onCheckoutCompleted (checkoutCompletedEvent : CheckoutCompletedEvent ) {}
176- override fun onCheckoutFailed (error : CheckoutException ) {}
177- override fun onCheckoutCanceled () {}
178- }
179- processor.onGeolocationPermissionsShowPrompt(origin, mockCallback)
180- verify(mockCallback).invoke(origin, true , true )
211+ fun testOnGeolocationPermissionsShowPrompt_withNoManifestPermission () {
212+ // Simulate no permissions declared in the manifest
213+ whenever(packageManager.getPackageInfo(context.packageName, PackageManager .GET_PERMISSIONS ))
214+ .thenThrow(PackageManager .NameNotFoundException ())
215+ processor.onGeolocationPermissionsShowPrompt(" http://shopify.com" , mockCallback)
216+ verify(mockCallback).invoke(" http://shopify.com" , false , false )
181217 }
182218
183219 @Test
184- fun `onGeolocationPermissionsShowPrompt should not invoke callback if overridden with no-op` () {
185- val overriddenProcessor = object : DefaultCheckoutEventProcessor (mock(), mock()) {
186- override fun onCheckoutCompleted (checkoutCompletedEvent : CheckoutCompletedEvent ) {}
187- override fun onCheckoutFailed (error : CheckoutException ) {}
188- override fun onCheckoutCanceled () {}
189- override fun onGeolocationPermissionsShowPrompt (origin : String , callback : GeolocationPermissions .Callback ) {}
190- }
191- overriddenProcessor.onGeolocationPermissionsShowPrompt(" http://shopify.com" , mockCallback)
192- verify(mockCallback, times(0 )).invoke(any(), any(), any())
220+ fun testOnGeolocationPermissionsShowPrompt_withManifestPermissionGranted () {
221+ // Simulate permissions declared in the manifest
222+ val permissions =
223+ arrayOf(
224+ Manifest .permission.ACCESS_FINE_LOCATION ,
225+ Manifest .permission.ACCESS_COARSE_LOCATION
226+ )
227+ whenever(packageManager.getPackageInfo(context.packageName, PackageManager .GET_PERMISSIONS ))
228+ .thenReturn(mockPackageInfo(permissions))
229+
230+ // Simulate runtime permission granted
231+ whenever(context.checkSelfPermission(Manifest .permission.ACCESS_FINE_LOCATION ))
232+ .thenReturn(PackageManager .PERMISSION_GRANTED )
233+ whenever(context.checkSelfPermission(Manifest .permission.ACCESS_COARSE_LOCATION ))
234+ .thenReturn(PackageManager .PERMISSION_GRANTED )
235+
236+ processor.onGeolocationPermissionsShowPrompt(" http://shopify.com" , mockCallback)
237+
238+ verify(mockCallback).invoke(" http://shopify.com" , true , true )
193239 }
194240
241+ @Test
242+ fun testOnGeolocationPermissionsShowPrompt_withManifestPermissionDenied () {
243+ // Simulate permissions declared in the manifest
244+ val permissions =
245+ arrayOf(
246+ Manifest .permission.ACCESS_FINE_LOCATION ,
247+ Manifest .permission.ACCESS_COARSE_LOCATION
248+ )
249+ whenever(packageManager.getPackageInfo(context.packageName, PackageManager .GET_PERMISSIONS ))
250+ .thenReturn(mockPackageInfo(permissions))
251+
252+ // Simulate runtime permission denied
253+ whenever(context.checkSelfPermission(Manifest .permission.ACCESS_FINE_LOCATION ))
254+ .thenReturn(PackageManager .PERMISSION_DENIED )
255+ whenever(context.checkSelfPermission(Manifest .permission.ACCESS_COARSE_LOCATION ))
256+ .thenReturn(PackageManager .PERMISSION_DENIED )
257+
258+ processor.onGeolocationPermissionsShowPrompt(" http://shopify.com" , mockCallback)
259+
260+ verify(mockCallback).invoke(" http://shopify.com" , false , false )
261+ }
262+
263+ // Private
264+
195265 private fun processor (activity : ComponentActivity ): DefaultCheckoutEventProcessor {
196- return object : DefaultCheckoutEventProcessor (activity) {
266+ return object : DefaultCheckoutEventProcessor (activity) {
197267 override fun onCheckoutCompleted (checkoutCompletedEvent : CheckoutCompletedEvent ) {}
198268 override fun onCheckoutFailed (error : CheckoutException ) {}
199269 override fun onCheckoutCanceled () {}
200270 override fun onWebPixelEvent (event : PixelEvent ) {}
201271 }
202272 }
273+
274+ private fun mockPackageInfo (permissions : Array <String >): PackageInfo {
275+ return PackageInfo ().apply { requestedPermissions = permissions }
276+ }
277+
278+ private class TestCheckoutEventProcessor (context : Context ) :
279+ DefaultCheckoutEventProcessor (context) {
280+ override fun onCheckoutCompleted (checkoutCompletedEvent : CheckoutCompletedEvent ) {}
281+ override fun onCheckoutFailed (error : CheckoutException ) {}
282+ override fun onCheckoutCanceled () {}
283+ }
203284}
0 commit comments