Skip to content

Commit

Permalink
feat(ramp): add sell deeplink (#8016)
Browse files Browse the repository at this point in the history
## **Description**

This PR adds the handling for the Sell flow deeplink, the same way we
did for Buy flow in
#5743:

This PR adds support for metamask://sell-crypto and
https://metamask.app.link/sell-crypto, these will open the sell flow.
## **Related issues**

Fixes:

## **Manual testing steps**

1. Navigate to `metamask://sell-crypto` or
https://metamask.app.link/sell-crypto
2. Sell flow must open

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've clearly explained what problem this PR is solving and how it
is solved.
- [x] I've linked related issues
- [x] I've included manual testing steps
- [x] I've included screenshots/recordings if applicable
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
- [x] I’ve properly set the pull request status:
  - [x] In case it's not yet "ready for review", I've set it to "draft".
- [x] In case it's "ready for review", I've changed it from "draft" to
"non-draft".

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
wachunei authored Dec 8, 2023
1 parent 444b319 commit 547cf76
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 1 deletion.
2 changes: 2 additions & 0 deletions app/constants/deeplinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export enum ACTIONS {
CONNECT = 'connect',
ANDROID_SDK = 'bind',
BUY_CRYPTO = 'buy-crypto',
SELL_CRYPTO = 'sell-crypto',
EMPTY = '',
}

Expand All @@ -36,5 +37,6 @@ export const PREFIXES = {
[ACTIONS.CONNECT]: '',
[ACTIONS.ANDROID_SDK]: '',
[ACTIONS.BUY_CRYPTO]: '',
[ACTIONS.SELL_CRYPTO]: '',
METAMASK: 'metamask://',
};
6 changes: 6 additions & 0 deletions app/core/DeeplinkManager/DeeplinkManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ describe('DeeplinkManager', () => {
deeplinkManager._handleBuyCrypto();
expect(mockNavigation.navigate).toHaveBeenCalledWith('RampBuy');
});

it('should handle sell crypto action correctly', () => {
deeplinkManager._handleSellCrypto();
expect(mockNavigation.navigate).toHaveBeenCalledWith('RampSell');
});

it('should parse deeplinks correctly', () => {
const url = 'http://example.com';
const browserCallBack = jest.fn();
Expand Down
4 changes: 4 additions & 0 deletions app/core/DeeplinkManager/DeeplinkManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class DeeplinkManager {
this.navigation.navigate(Routes.RAMP.BUY);
}

_handleSellCrypto() {
this.navigation.navigate(Routes.RAMP.SELL);
}

parse(
url: string,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jest.mock('../../../core/NativeModules', () => ({
describe('handleMetaMaskProtocol', () => {
const mockParse = jest.fn();
const mockHandleBuyCrypto = jest.fn();
const mockHandleSellCrypto = jest.fn();
const mockHandleBrowserUrl = jest.fn();
const mockConnectToChannel = jest.fn();
const mockGetConnections = jest.fn();
Expand All @@ -37,6 +38,7 @@ describe('handleMetaMaskProtocol', () => {
const instance = {
parse: mockParse,
_handleBuyCrypto: mockHandleBuyCrypto,
_handleSellCrypto: mockHandleSellCrypto,
_handleBrowserUrl: mockHandleBrowserUrl,
} as unknown as DeeplinkManager;

Expand Down Expand Up @@ -216,4 +218,23 @@ describe('handleMetaMaskProtocol', () => {
expect(mockHandleBuyCrypto).toHaveBeenCalled();
});
});

describe('when url start with ${PREFIXES.METAMASK}${ACTIONS.SELL_CRYPTO}', () => {
beforeEach(() => {
url = `${PREFIXES.METAMASK}${ACTIONS.SELL_CRYPTO}`;
});

it('should call _handleSellCrypto', () => {
handleMetaMaskDeeplink({
instance,
handled,
params,
url,
origin,
wcURL,
});

expect(mockHandleSellCrypto).toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export function handleMetaMaskDeeplink({
});
} else if (url.startsWith(`${PREFIXES.METAMASK}${ACTIONS.BUY_CRYPTO}`)) {
instance._handleBuyCrypto();
} else if (url.startsWith(`${PREFIXES.METAMASK}${ACTIONS.SELL_CRYPTO}`)) {
instance._handleSellCrypto();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jest.mock('../../../core/NativeModules', () => ({
describe('handleUniversalLinks', () => {
const mockParse = jest.fn();
const mockHandleBuyCrypto = jest.fn();
const mockHandleSellCrypto = jest.fn();
const mockHandleBrowserUrl = jest.fn();
const mockConnectToChannel = jest.fn();
const mockGetConnections = jest.fn();
Expand All @@ -37,6 +38,7 @@ describe('handleUniversalLinks', () => {
const instance = {
parse: mockParse,
_handleBuyCrypto: mockHandleBuyCrypto,
_handleSellCrypto: mockHandleSellCrypto,
_handleBrowserUrl: mockHandleBrowserUrl,
} as unknown as DeeplinkManager;

Expand Down Expand Up @@ -306,8 +308,32 @@ describe('handleUniversalLinks', () => {
});
});

describe('ACTIONS.SELL_CRYPTO', () => {
it('should call instance._handleSellCrypto if action is ACTIONS.SELL_CRYPTO', () => {
urlObj = {
hostname: AppConstants.MM_UNIVERSAL_LINK_HOST,
pathname: `/${ACTIONS.SELL_CRYPTO}/additional/path`,
href: 'test-href',
} as ReturnType<typeof extractURLParams>['urlObj'];

handleUniversalLink({
instance,
handled,
urlObj,
params,
browserCallBack: mockBrowserCallBack,
origin,
wcURL,
url,
});

expect(handled).toHaveBeenCalled();
expect(mockHandleSellCrypto).toHaveBeenCalledTimes(1);
});
});

describe('default condition', () => {
it('should call instance._handleBrowserUrl if action is not ACTIONS.BUY_CRYPTO', () => {
it('should call instance._handleBrowserUrl if action is not ACTIONS.BUY_CRYPTO or ACTIONS.SELL_CRYPTO', () => {
urlObj = {
hostname: AppConstants.MM_UNIVERSAL_LINK_HOST,
pathname: `/other-action/additional/path`,
Expand Down
2 changes: 2 additions & 0 deletions app/core/DeeplinkManager/ParseManager/handleUniversalLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ function handleUniversalLink({
instance.parse(deeplinkUrl, { browserCallBack, origin });
} else if (action === ACTIONS.BUY_CRYPTO) {
instance._handleBuyCrypto();
} else if (action === ACTIONS.SELL_CRYPTO) {
instance._handleSellCrypto();
} else {
// If it's our universal link or Apple store deep link don't open it in the browser
if (
Expand Down

0 comments on commit 547cf76

Please sign in to comment.