Repository navigation
test(SDK-615): inbox message display URL handling #940
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -2,11 +2,13 @@ | |||
|
|
||||
| ### Fixes | ||||
|
|
||||
| - Inbox message HTML links: unknown `iterable://` URLs no longer fall through to `urlHandler`; only `iterable://delete` and `iterable://dismiss` are handled as SDK actions (SDK-615, SDK-633). | ||||
| - Fixed `Iterable.trackPushOpenWithCampaignId` on Android so the `appAlreadyRunning` argument is forwarded to the native SDK instead of always being sent as `false`. | ||||
| - `Iterable.inAppManager.showMessage` now rejects on iOS when the message id is empty or no longer in the native queue, matching Android. Previously the promise never settled. | ||||
|
|
||||
| ### Updates | ||||
|
|
||||
| - Added unit tests for inbox message link handling in `IterableInboxMessageDisplay` (SDK-615). | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as in #937
Suggested change
|
||||
| - Added optional placement IDs to `Iterable.embeddedManager.syncMessages()` so apps can sync embedded messages for specific placements only (SDK-751). When omitted, null, or empty, behavior matches the previous sync-all call. | ||||
| - **Android:** Scoped sync (`syncMessages([id, β¦])`) matches the pinned iterableapi behavior and may remove cached messages for placements not included in the sync response (SDK-798). iOS preserves unrequested placements. Prefer `syncMessages()` without placement IDs on Android until the native fix ships and the Android SDK pin is bumped. | ||||
| - Added `IterableInAppMessage.jsonOnly` so `inAppHandler` and in-app message fetches can distinguish JSON-only messages from HTML in-apps (SDK-750). | ||||
|
|
||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,246 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { View } from 'react-native'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| act, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fireEvent, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| render, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type RenderResult, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| waitFor, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@testing-library/react-native'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { MockLinking } from '../../__mocks__/MockLinking'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { MockRNIterableAPI } from '../../__mocks__/MockRNIterableAPI'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Iterable } from '../../core/classes/Iterable'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableActionContext } from '../../core/classes/IterableActionContext'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableConfig } from '../../core/classes/IterableConfig'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableEdgeInsets } from '../../core/classes/IterableEdgeInsets'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableActionSource } from '../../core/enums/IterableActionSource'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableHtmlInAppContent } from '../../inApp/classes/IterableHtmlInAppContent'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableInAppMessage } from '../../inApp/classes/IterableInAppMessage'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableInAppTrigger } from '../../inApp/classes/IterableInAppTrigger'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableInboxMetadata } from '../../inApp/classes/IterableInboxMetadata'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableInAppTriggerType } from '../../inApp/enums/IterableInAppTriggerType'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableInAppCloseSource } from '../../inApp/enums/IterableInAppCloseSource'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableInAppLocation } from '../../inApp/enums/IterableInAppLocation'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { IterableInboxRowViewModel } from '../types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IterableInboxMessageDisplay } from './IterableInboxMessageDisplay'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| describe('IterableInboxMessageDisplay', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const messageId = 'msg-1'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rowViewModel: IterableInboxRowViewModel = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: 'T', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| read: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inAppMessage: new IterableInAppMessage( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messageId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new IterableInAppTrigger(IterableInAppTriggerType.never), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new IterableInboxMetadata('Hello', undefined, undefined), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const htmlContent = new IterableHtmlInAppContent( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new IterableEdgeInsets(0, 0, 0, 0), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '<html><body></body></html>' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let deleteRow: jest.Mock; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let returnToInbox: jest.Mock; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let urlHandler: jest.Mock; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let customActionHandler: jest.Mock; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let trackInAppClickSpy: jest.SpyInstance; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let trackInAppCloseSpy: jest.SpyInstance; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| beforeEach(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deleteRow = jest.fn(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| returnToInbox = jest.fn((callback?: () => void) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callback?.(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| urlHandler = jest.fn(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customActionHandler = jest.fn(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = new IterableConfig(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config.urlHandler = urlHandler; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config.customActionHandler = customActionHandler; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Iterable.savedConfig = config; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackInAppClickSpy = jest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .spyOn(Iterable, 'trackInAppClick') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .mockImplementation(() => {}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackInAppCloseSpy = jest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .spyOn(Iterable, 'trackInAppClose') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .mockImplementation(() => {}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MockRNIterableAPI.trackInAppClick.mockClear(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MockRNIterableAPI.trackInAppClose.mockClear(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MockLinking.openURL.mockClear(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| afterEach(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackInAppClickSpy.mockRestore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackInAppCloseSpy.mockRestore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Iterable.savedConfig = new IterableConfig(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function renderWithContent(): Promise<RenderResult> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utils = render( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <IterableInboxMessageDisplay | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rowViewModel={rowViewModel} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inAppContentPromise={Promise.resolve(htmlContent)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| returnToInbox={returnToInbox} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deleteRow={deleteRow} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contentWidth={320} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isPortrait | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await act(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await Promise.resolve(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return utils; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Global setup mocks `WebView` as `View`; pick the node wired with `onMessage`. */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function postWebViewMessage(utils: RenderResult, url: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const candidates = utils.UNSAFE_getAllByType(View); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const webView = candidates.find( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (node) => typeof node.props.onMessage === 'function' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(webView).toBeDefined(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const onMessage = webView!.props.onMessage as ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e: { nativeEvent: { data: string } } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onMessage({ nativeEvent: { data: url } }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should open http(s) in the system browser and return to the inbox', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utils = await renderWithContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const url = 'https://example.com/path'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postWebViewMessage(utils, url); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(trackInAppClickSpy).toHaveBeenCalledWith( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rowViewModel.inAppMessage, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IterableInAppLocation.inbox, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(trackInAppCloseSpy).toHaveBeenCalledWith( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rowViewModel.inAppMessage, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IterableInAppLocation.inbox, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IterableInAppCloseSource.link, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(returnToInbox).toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(MockLinking.openURL).toHaveBeenCalledWith(url); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(deleteRow).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(urlHandler).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should delete the row and return to the inbox for iterable://delete', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utils = await renderWithContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postWebViewMessage(utils, 'iterable://delete'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(deleteRow).toHaveBeenCalledWith(messageId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(returnToInbox).toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(urlHandler).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(MockLinking.openURL).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should return to the inbox for iterable://dismiss without deleting', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utils = await renderWithContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postWebViewMessage(utils, 'iterable://dismiss'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(returnToInbox).toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(deleteRow).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(urlHandler).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest adding |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should invoke customActionHandler with the action type for action:// URLs', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utils = await renderWithContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const url = 'action://foo'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postWebViewMessage(utils, url); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await waitFor(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(customActionHandler).toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(customActionHandler).toHaveBeenCalledWith( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect.objectContaining({ type: 'foo' }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect.any(IterableActionContext) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [, context] = customActionHandler.mock.calls[0]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(context.source).toBe(IterableActionSource.inApp); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(returnToInbox).toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(urlHandler).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should swallow unknown iterable:// URLs without calling urlHandler or returning to inbox', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utils = await renderWithContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postWebViewMessage(utils, 'iterable://foo'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(returnToInbox).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(urlHandler).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(MockLinking.openURL).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(deleteRow).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+184
to
+193
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test locks in the open-message behaviour, and it never checks
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should pass other URLs to urlHandler', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utils = await renderWithContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const url = 'myapp://screen'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postWebViewMessage(utils, url); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await waitFor(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(urlHandler).toHaveBeenCalledWith(url, expect.any(IterableActionContext)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(returnToInbox).toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(MockLinking.openURL).not.toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should forward click tracking to the native bridge', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackInAppClickSpy.mockRestore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackInAppCloseSpy.mockRestore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utils = await renderWithContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const url = 'https://example.com/x'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postWebViewMessage(utils, url); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(MockRNIterableAPI.trackInAppClick).toHaveBeenCalledWith( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messageId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IterableInAppLocation.inbox, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(MockRNIterableAPI.trackInAppClose).toHaveBeenCalledWith( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messageId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IterableInAppLocation.inbox, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IterableInAppCloseSource.link, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should track close when the back button is pressed', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackInAppClickSpy.mockRestore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trackInAppCloseSpy.mockRestore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { getByText } = await renderWithContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fireEvent.press(getByText('Inbox')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(returnToInbox).toHaveBeenCalled(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(MockRNIterableAPI.trackInAppClose).toHaveBeenCalledWith( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messageId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IterableInAppLocation.inbox, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IterableInAppCloseSource.back, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -163,6 +163,9 @@ export const IterableInboxMessageDisplay = ({ | |||||||||||||||
| const source = IterableActionSource.inApp; | ||||||||||||||||
| const context = new IterableActionContext(action, source); | ||||||||||||||||
|
|
||||||||||||||||
| // Track before routing: aligns with native HTML in-app (click/close first, | ||||||||||||||||
| // then iterable:// handling). Unknown iterable:// paths still get these | ||||||||||||||||
| // events while skipping urlHandler / returnToInbox below. | ||||||||||||||||
|
Comment on lines
+166
to
+168
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment says unknown paths skip
Suggested change
|
||||||||||||||||
| Iterable.trackInAppClick( | ||||||||||||||||
| rowViewModel.inAppMessage, | ||||||||||||||||
| IterableInAppLocation.inbox, | ||||||||||||||||
|
|
@@ -181,6 +184,9 @@ export const IterableInboxMessageDisplay = ({ | |||||||||||||||
| //handle dismiss action | ||||||||||||||||
| } else if (URL === 'iterable://dismiss') { | ||||||||||||||||
| returnToInbox(); | ||||||||||||||||
| // iterable:// is reserved β only delete/dismiss are SDK actions (SDK-633) | ||||||||||||||||
| } else if (URL.startsWith('iterable://')) { | ||||||||||||||||
| return; | ||||||||||||||||
|
Comment on lines
+187
to
+189
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This branch tracks a close but leaves the message open. Lines 169β179 already sent Native in-apps close the message after every link click, including an unknown
So "swallow, same as native" in SDK-633 means: close the message and call no handler.
Suggested change
SDK-615 AC4 ("no navigation") should then read "no |
||||||||||||||||
| //handle external link | ||||||||||||||||
| } else if (URL.slice(0, 4) === 'http') { | ||||||||||||||||
| returnToInbox(() => Linking.openURL(URL)); | ||||||||||||||||
|
|
||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This changes behaviour for anyone who used
iterable://β¦links as deep links in inbox HTML. The bullet should tell them what to use instead.action://nameis already documented oncustomActionHandlerinIterableConfig.ts.