Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(deeplinks): get url from the correct field for CT events #6356

Merged
merged 1 commit into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions __mocks__/@react-native-firebase/dynamic-links.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const getInitialLink = jest.fn()
const buildShortLink = jest.fn()
const buildLink = jest.fn()
const onLink = jest.fn()

export default function links() {
return {
getInitialLink,
buildShortLink,
buildLink,
onLink,
}
}
3 changes: 3 additions & 0 deletions __mocks__/clevertap-react-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ export default {
setPushToken: jest.fn(),
createNotificationChannel: jest.fn(),
registerForPush: jest.fn(),
getInitialUrl: jest.fn(),
addListener: jest.fn(),
removeListener: jest.fn(),
}
6 changes: 5 additions & 1 deletion src/app/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,11 @@
}

function* watchDeepLinks() {
yield* takeLatest(Actions.OPEN_DEEP_LINK, safely(handleDeepLink))
// using takeEvery over takeLatest because openScreen deep links could be
// fired by multiple handlers (one with isSecureOrigin and one without), and
// if takeLatest kills the call to the handler with isSecureOrigin, the deep
// link won't work.
yield* takeEvery(Actions.OPEN_DEEP_LINK, safely(handleDeepLink))

Check warning on line 330 in src/app/saga.ts

View check run for this annotation

Codecov / codecov/patch

src/app/saga.ts#L330

Added line #L330 was not covered by tests
}

export function* handleOpenUrl(action: OpenUrlAction) {
Expand Down
86 changes: 86 additions & 0 deletions src/app/useDeepLinks.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { act, renderHook } from '@testing-library/react-native'
import CleverTap from 'clevertap-react-native'
import React from 'react'
import { Linking } from 'react-native'
import { Provider } from 'react-redux'
import { useDeepLinks } from 'src/app/useDeepLinks'
import { createMockStore } from 'test/utils'

describe('useDeepLinks', () => {
let cleverTapListenerCallback: Function
let linkingListenerCallback: Function

beforeEach(() => {
jest.clearAllMocks()
jest.mocked(CleverTap.addListener).mockImplementation((event, callback) => {
if (event === 'CleverTapPushNotificationClicked') {
cleverTapListenerCallback = callback
}
})
jest.mocked(Linking.addEventListener).mockImplementation((event, callback) => {
if (event === 'url') {
linkingListenerCallback = callback
}
return {
remove: jest.fn(),
} as any
})
})

it('should handle clevertap push notifications with deep links', async () => {
const store = createMockStore()
renderHook(() => useDeepLinks(), {
wrapper: (component) => (
<Provider store={store}>{component?.children ? component.children : component}</Provider>
),
})

await act(() => {
cleverTapListenerCallback({ wzrk_dl: 'some-link' })
})

expect(store.getActions()).toEqual([
{
deepLink: 'some-link',
isSecureOrigin: true,
type: 'APP/OPEN_DEEP_LINK',
},
])
})

it('should not open deeplink if clevertap event does not have a deep link', async () => {
const store = createMockStore()
renderHook(() => useDeepLinks(), {
wrapper: (component) => (
<Provider store={store}>{component?.children ? component.children : component}</Provider>
),
})

await act(() => {
cleverTapListenerCallback({})
})

expect(store.getActions()).toEqual([])
})

it('should handle linking events with deep links', async () => {
const store = createMockStore()
renderHook(() => useDeepLinks(), {
wrapper: (component) => (
<Provider store={store}>{component?.children ? component.children : component}</Provider>
),
})

await act(() => {
linkingListenerCallback({ url: 'some-link' })
})

expect(store.getActions()).toEqual([
{
deepLink: 'some-link',
isSecureOrigin: false,
type: 'APP/OPEN_DEEP_LINK',
},
])
})
})
12 changes: 7 additions & 5 deletions src/app/useDeepLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import dynamicLinks from '@react-native-firebase/dynamic-links'
import CleverTap from 'clevertap-react-native'
import { useEffect, useState } from 'react'
import { useAsync } from 'react-async-hook'
import { Linking, Platform } from 'react-native'
import { Linking } from 'react-native'
import { deepLinkDeferred, openDeepLink } from 'src/app/actions'
import { pendingDeepLinkSelector } from 'src/app/selectors'
import { DYNAMIC_LINK_DOMAIN_URI_PREFIX, FIREBASE_ENABLED } from 'src/config'
Expand Down Expand Up @@ -62,7 +62,7 @@ export const useDeepLinks = () => {
}

useAsync(async () => {
// Handles opening Clevertap deeplinks when app is closed / in background
// Handles opening Clevertap deeplinks when app is closed
// @ts-expect-error the clevertap ts definition has url as an object, but it
// is a string!
CleverTap.getInitialUrl(async (err: any, url: string) => {
Expand Down Expand Up @@ -94,17 +94,19 @@ export const useDeepLinks = () => {
}, [])

useEffect(() => {
// Handles opening Clevertap deeplinks when app is open
// Handles opening Clevertap deeplinks when app is open.
CleverTap.addListener('CleverTapPushNotificationClicked', async (event: any) => {
Logger.debug('useDeepLinks/useEffect', 'CleverTapPushNotificationClicked', event)
// Url location differs for iOS and Android
const url = Platform.OS === 'ios' ? event.customExtras['wzrk_dl'] : event['wzrk_dl']
const url = event['wzrk_dl']
if (url) {
Logger.debug('useDeepLinks/useEffect', 'CleverTapPushNotificationClicked, opening url', url)
handleOpenURL({ url }, true)
}
})

// Handles opening any deep links, this listener is also triggered when a
// its a clevertap push notification or when the app is closed, so the
// openDeepLink action could be dispatched multiple times in those cases.
const linkingEventListener = Linking.addEventListener('url', (event) => {
Logger.debug('useDeepLinks/useEffect', 'Linking url event', event)
handleOpenURL(event)
Expand Down
Loading