-
Notifications
You must be signed in to change notification settings - Fork 232
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fund button - setupOnrampEventListeners util for setting up onSuccess…
…, onEvent and onExit callbacks (#1626)
- Loading branch information
Showing
7 changed files
with
418 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; | ||
import type { EventMetadata } from '../types'; | ||
import { setupOnrampEventListeners } from './setupOnrampEventListeners'; | ||
import { subscribeToWindowMessage } from './subscribeToWindowMessage'; | ||
|
||
vi.mock('./subscribeToWindowMessage', () => ({ | ||
subscribeToWindowMessage: vi.fn(), | ||
})); | ||
|
||
describe('setupOnrampEventListeners', () => { | ||
let unsubscribe: ReturnType<typeof vi.fn>; | ||
|
||
beforeEach(() => { | ||
unsubscribe = vi.fn(); | ||
}); | ||
|
||
afterEach(() => { | ||
vi.resetAllMocks(); | ||
}); | ||
|
||
it('should call subscribeToWindowMessage with correct parameters', () => { | ||
const onEvent = vi.fn(); | ||
const onExit = vi.fn(); | ||
const onSuccess = vi.fn(); | ||
const host = 'https://example.com'; | ||
|
||
setupOnrampEventListeners({ onEvent, onExit, onSuccess, host }); | ||
|
||
expect(subscribeToWindowMessage).toHaveBeenCalledWith({ | ||
allowedOrigin: host, | ||
onMessage: expect.any(Function), | ||
}); | ||
}); | ||
|
||
it('should call onSuccess callback when success event is received', () => { | ||
const onEvent = vi.fn(); | ||
const onExit = vi.fn(); | ||
const onSuccess = vi.fn(); | ||
const host = 'https://example.com'; | ||
|
||
setupOnrampEventListeners({ onEvent, onExit, onSuccess, host }); | ||
|
||
const eventMetadata: EventMetadata = { eventName: 'success' }; | ||
|
||
vi.mocked(subscribeToWindowMessage).mock.calls[0][0].onMessage( | ||
eventMetadata, | ||
); | ||
|
||
expect(onSuccess).toHaveBeenCalled(); | ||
expect(onExit).not.toHaveBeenCalled(); | ||
expect(onEvent).toHaveBeenCalledWith(eventMetadata); | ||
}); | ||
|
||
it('should call onExit callback when exit event is received', () => { | ||
const onEvent = vi.fn(); | ||
const onExit = vi.fn(); | ||
const onSuccess = vi.fn(); | ||
const host = 'https://example.com'; | ||
|
||
setupOnrampEventListeners({ onEvent, onExit, onSuccess, host }); | ||
|
||
const eventMetadata: EventMetadata = { | ||
eventName: 'exit', | ||
error: { | ||
errorType: 'internal_error', | ||
}, | ||
}; | ||
vi.mocked(subscribeToWindowMessage).mock.calls[0][0].onMessage( | ||
eventMetadata, | ||
); | ||
|
||
expect(onExit).toHaveBeenCalledWith(eventMetadata.error); | ||
expect(onSuccess).not.toHaveBeenCalled(); | ||
expect(onEvent).toHaveBeenCalledWith(eventMetadata); | ||
}); | ||
|
||
it('should call onEvent callback for any event received', () => { | ||
const onEvent = vi.fn(); | ||
const onExit = vi.fn(); | ||
const onSuccess = vi.fn(); | ||
const host = 'https://example.com'; | ||
|
||
setupOnrampEventListeners({ onEvent, onExit, onSuccess, host }); | ||
|
||
const eventMetadata: EventMetadata = { eventName: 'success' }; | ||
vi.mocked(subscribeToWindowMessage).mock.calls[0][0].onMessage( | ||
eventMetadata, | ||
); | ||
|
||
expect(onEvent).toHaveBeenCalledWith(eventMetadata); | ||
}); | ||
|
||
it('should return the unsubscribe function', () => { | ||
const onEvent = vi.fn(); | ||
const onExit = vi.fn(); | ||
const onSuccess = vi.fn(); | ||
const host = 'https://example.com'; | ||
|
||
vi.mocked(subscribeToWindowMessage).mockReturnValue(unsubscribe); | ||
|
||
const result = setupOnrampEventListeners({ | ||
onEvent, | ||
onExit, | ||
onSuccess, | ||
host, | ||
}); | ||
|
||
expect(result).toBe(unsubscribe); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { DEFAULT_ONRAMP_URL } from '../constants'; | ||
import type { EventMetadata, OnRampError } from '../types'; | ||
import { subscribeToWindowMessage } from './subscribeToWindowMessage'; | ||
|
||
type SetupOnrampEventListenersParams = { | ||
host?: string; | ||
onSuccess?: () => void; | ||
onExit?: (error?: OnRampError) => void; | ||
onEvent?: (event: EventMetadata) => void; | ||
}; | ||
|
||
/** | ||
* Subscribes to events from the Coinbase Onramp widget. | ||
* @param onEvent - Callback for when any event is received. | ||
* @param onExit - Callback for when an exit event is received. | ||
* @param onSuccess - Callback for when a success event is received. | ||
* @returns a function to unsubscribe from the event listener. | ||
*/ | ||
export function setupOnrampEventListeners({ | ||
onEvent, | ||
onExit, | ||
onSuccess, | ||
host = DEFAULT_ONRAMP_URL, | ||
}: SetupOnrampEventListenersParams) { | ||
const unsubscribe = subscribeToWindowMessage({ | ||
allowedOrigin: host, | ||
onMessage: (data) => { | ||
const metadata = data as EventMetadata; | ||
|
||
if (metadata.eventName === 'success') { | ||
onSuccess?.(); | ||
} | ||
if (metadata.eventName === 'exit') { | ||
onExit?.(metadata.error); | ||
} | ||
onEvent?.(metadata); | ||
}, | ||
}); | ||
|
||
return unsubscribe; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; | ||
import { | ||
MessageCodes, | ||
subscribeToWindowMessage, | ||
} from './subscribeToWindowMessage'; | ||
|
||
describe('subscribeToWindowMessage', () => { | ||
let unsubscribe: () => void; | ||
const DEFAULT_ORIGIN = 'https://default.origin'; | ||
// biome-ignore lint/suspicious/noExplicitAny: <explanation> | ||
const mockMessageEvent = (data: any, origin = DEFAULT_ORIGIN) => | ||
new MessageEvent('message', { data, origin }); | ||
|
||
beforeEach(() => { | ||
unsubscribe = () => {}; | ||
}); | ||
|
||
afterEach(() => { | ||
unsubscribe(); | ||
}); | ||
|
||
it('should subscribe to window message and call onMessage when message is received', async () => { | ||
const onMessage = vi.fn(); | ||
unsubscribe = subscribeToWindowMessage({ | ||
onMessage, | ||
allowedOrigin: DEFAULT_ORIGIN, | ||
}); | ||
|
||
const event = mockMessageEvent({ | ||
eventName: MessageCodes.Event, | ||
data: { key: 'value' }, | ||
}); | ||
window.dispatchEvent(event); | ||
|
||
//wait for the async code to run | ||
await Promise.resolve(); | ||
|
||
expect(onMessage).toHaveBeenCalledWith({ key: 'value' }); | ||
}); | ||
|
||
it('should not call onMessage if the origin is not allowed', async () => { | ||
const onMessage = vi.fn(); | ||
subscribeToWindowMessage({ | ||
onMessage, | ||
allowedOrigin: 'https://not.allowed.origin', | ||
}); | ||
|
||
const event = mockMessageEvent({ | ||
eventName: MessageCodes.Event, | ||
data: { key: 'value' }, | ||
}); | ||
window.dispatchEvent(event); | ||
|
||
//wait for the async code to run | ||
await Promise.resolve(); | ||
|
||
expect(onMessage).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should validate the origin using onValidateOrigin callback', async () => { | ||
const onMessage = vi.fn(); | ||
const onValidateOrigin = vi.fn().mockResolvedValue(true); | ||
subscribeToWindowMessage({ | ||
onMessage, | ||
allowedOrigin: DEFAULT_ORIGIN, | ||
onValidateOrigin, | ||
}); | ||
|
||
const event = mockMessageEvent({ | ||
eventName: MessageCodes.Event, | ||
data: { key: 'value' }, | ||
}); | ||
window.dispatchEvent(event); | ||
|
||
//wait for the async code to run | ||
await Promise.resolve(); | ||
|
||
expect(onValidateOrigin).toHaveBeenCalledWith(DEFAULT_ORIGIN); | ||
expect(onMessage).toHaveBeenCalledWith({ key: 'value' }); | ||
}); | ||
|
||
it('should not call onMessage if onValidateOrigin returns false', async () => { | ||
const onMessage = vi.fn(); | ||
const onValidateOrigin = vi.fn().mockResolvedValue(false); | ||
subscribeToWindowMessage({ | ||
onMessage, | ||
allowedOrigin: DEFAULT_ORIGIN, | ||
onValidateOrigin, | ||
}); | ||
|
||
const event = mockMessageEvent({ | ||
eventName: MessageCodes.Event, | ||
data: { key: 'value' }, | ||
}); | ||
window.dispatchEvent(event); | ||
|
||
//wait for the async code to run | ||
await Promise.resolve(); | ||
|
||
expect(onValidateOrigin).toHaveBeenCalledWith(DEFAULT_ORIGIN); | ||
expect(onMessage).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should not call onMessage if the message code is not "event"', async () => { | ||
const onMessage = vi.fn(); | ||
subscribeToWindowMessage({ | ||
onMessage, | ||
allowedOrigin: DEFAULT_ORIGIN, | ||
}); | ||
|
||
const event = mockMessageEvent({ | ||
eventName: 'not-event', | ||
data: { key: 'value' }, | ||
}); | ||
window.dispatchEvent(event); | ||
|
||
//wait for the async code to run | ||
await Promise.resolve(); | ||
|
||
expect(onMessage).not.toHaveBeenCalled(); | ||
}); | ||
}); |
Oops, something went wrong.