Skip to content

Commit

Permalink
chore: MMI move custody component to TS (#26096)
Browse files Browse the repository at this point in the history
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Moves Custody component to TS.

## **Related issues**

Fixes:

## **Manual testing steps**

1. Go to this page...
2.
3.

## **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**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **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.

---------

Co-authored-by: Albert Olive <[email protected]>
  • Loading branch information
zone-live and albertolive authored Jul 26, 2024
1 parent fddb0a4 commit 08c7333
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ import {
TextVariant,
Display,
} from '../../../helpers/constants/design-system';

type LabelItem = {
key: string;
value: string;
};
import { LabelItem } from '../../../pages/institutional/custody/custody';

type CustodyLabelsProps = {
labels: LabelItem[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { useI18nContext } from '../../../hooks/useI18nContext';
type QRCodeModalProps = {
onClose: () => void;
custodianName?: string;
custodianURL: string;
custodianURL: string | undefined;
setQrConnectionRequest: (message: string) => void;
};

Expand Down
29 changes: 5 additions & 24 deletions ui/pages/institutional/account-list/account-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,16 @@ import {
Text,
} from '../../../components/component-library';
import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard';

type CustodianDetails = {
coin: string;
id: string;
};

type LabelItem = {
key: string;
value: string;
};

type Account = {
address: string;
name: string;
custodianDetails?: CustodianDetails;
labels?: LabelItem[];
chainId?: string;
balance?: string;
token?: string;
};
import { Account } from '../custody/custody';

type CustodyAccountListProps = {
rawList?: boolean;
accounts: Account[];
accounts: Account[] | null | undefined;
onAccountChange?: (account: Account) => void;
selectedAccounts?: { [key: string]: boolean };
onCancel?: () => void;
onAddAccounts?: (custody?: string) => void;
custody?: string;
custody?: string | null;
children?: React.ReactNode;
};

Expand Down Expand Up @@ -92,7 +73,7 @@ const CustodyAccountList: React.FC<CustodyAccountListProps> = ({
data-testid="custody-account-list"
>
{accounts
.sort((a, b) =>
?.sort((a, b) =>
a.name
.toLocaleLowerCase()
.localeCompare(b.name.toLocaleLowerCase()),
Expand Down Expand Up @@ -229,7 +210,7 @@ const CustodyAccountList: React.FC<CustodyAccountListProps> = ({
size={ButtonSize.Lg}
className="custody-account-list__button"
disabled={disabled}
onClick={() => onAddAccounts && onAddAccounts(custody)}
onClick={() => onAddAccounts && custody && onAddAccounts(custody)}
>
{t('connect')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { useI18nContext } from '../../../hooks/useI18nContext';
import { DEFAULT_ROUTE } from '../../../helpers/constants/routes';

type CustodianListViewProps = {
custodianList: object[];
custodianList: React.ReactNode[];
};

const CustodianListView: React.FC<CustodianListViewProps> = ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React from 'react';
import { Dispatch } from 'redux';
import configureMockStore from 'redux-mock-store';
import { fireEvent, waitFor, screen, act } from '@testing-library/react';
import thunk from 'redux-thunk';
import Fuse from 'fuse.js';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import { Account } from './custody';
import CustodyPage from '.';

const mockedConnectCustodyAddresses = jest
.fn()
.mockReturnValue({ type: 'TYPE' });
const mockedGetCustodianJWTList = jest
.fn()
.mockImplementation(() => async (dispatch) => {
.mockImplementation(() => async (dispatch: Dispatch) => {
const jwtList = ['jwt1', 'jwt2', 'jwt3'];
dispatch({ type: 'TYPE', payload: jwtList });
return jwtList;
Expand All @@ -29,7 +31,26 @@ jest.mock('../../../store/institutional/institution-background', () => ({
}),
}));

jest.mock('fuse.js');
jest.mock('fuse.js', () => {
return {
__esModule: true,
default: jest.fn().mockImplementation(() => {
return {
search: jest.fn().mockReturnValue([
{
name: 'Saturn Test A',
address: '0x123',
},
]),
setCollection: jest.fn(),
list: [],
};
}),
};
});

type MockedFuseType = jest.MockedClass<typeof Fuse>;
const MockedFuse = Fuse as unknown as MockedFuseType;

describe('CustodyPage', function () {
const mockStore = {
Expand Down Expand Up @@ -240,20 +261,22 @@ describe('CustodyPage', function () {
});

it('renders custody accounts list when I have accounts from connectRequest', async () => {
mockedGetCustodianAccounts.mockImplementation(() => async (dispatch) => {
const accounts = [
{
name: 'Saturn Test Name',
address: '0x123',
balance: '0x1',
custodianDetails: 'custodianDetails',
labels: [{ key: 'key', value: 'testLabels' }],
chanId: 'chanId',
},
];
dispatch({ type: 'TYPE', payload: accounts });
return accounts;
});
mockedGetCustodianAccounts.mockImplementation(
() => async (dispatch: Dispatch) => {
const accounts = [
{
name: 'Saturn Test Name',
address: '0x123',
balance: '0x1',
custodianDetails: 'custodianDetails',
labels: [{ key: 'key', value: 'testLabels' }],
chanId: 'chanId',
},
];
dispatch({ type: 'TYPE', payload: accounts });
return accounts;
},
);

const newMockStore = {
...mockStore,
Expand Down Expand Up @@ -288,11 +311,13 @@ describe('CustodyPage', function () {
});

it('renders custodian list, initiates connect custodian, displays jwt token list, clicks connect button, and finally shows "no accounts available" message', async () => {
mockedGetCustodianAccounts.mockImplementation(() => async (dispatch) => {
const accounts = [];
dispatch({ type: 'TYPE', payload: accounts });
return accounts;
});
mockedGetCustodianAccounts.mockImplementation(
() => async (dispatch: Dispatch) => {
const accounts: Account[] = [];
dispatch({ type: 'TYPE', payload: accounts });
return accounts;
},
);

act(() => {
renderWithProvider(<CustodyPage />, store);
Expand Down Expand Up @@ -354,10 +379,12 @@ describe('CustodyPage', function () {
},
];

mockedGetCustodianAccounts.mockImplementation(() => async (dispatch) => {
dispatch({ type: 'TYPE', payload: accounts });
return accounts;
});
mockedGetCustodianAccounts.mockImplementation(
() => async (dispatch: Dispatch) => {
dispatch({ type: 'TYPE', payload: accounts });
return accounts;
},
);

const newMockStore = {
...mockStore,
Expand Down Expand Up @@ -392,10 +419,12 @@ describe('CustodyPage', function () {
});

it('handles connection errors correctly', async () => {
mockedGetCustodianAccounts.mockImplementation(() => async (dispatch) => {
dispatch({ type: 'TYPE', payload: [] });
throw new Error('Test Error');
});
mockedGetCustodianAccounts.mockImplementation(
() => async (dispatch: Dispatch) => {
dispatch({ type: 'TYPE', payload: [] });
throw new Error('Test Error');
},
);

const newMockStore = {
...mockStore,
Expand Down Expand Up @@ -428,10 +457,12 @@ describe('CustodyPage', function () {
});

it('handles authentication errors correctly', async () => {
mockedGetCustodianAccounts.mockImplementation(() => async (dispatch) => {
dispatch({ type: 'TYPE', payload: [] });
throw new Error('401: Unauthorized');
});
mockedGetCustodianAccounts.mockImplementation(
() => async (dispatch: Dispatch) => {
dispatch({ type: 'TYPE', payload: [] });
throw new Error('401: Unauthorized');
},
);

const newMockStore = {
...mockStore,
Expand Down Expand Up @@ -518,18 +549,22 @@ describe('CustodyPage', function () {
},
];

mockedGetCustodianAccounts.mockImplementation(() => async (dispatch) => {
dispatch({ type: 'TYPE', payload: accounts });
return accounts;
});
mockedGetCustodianAccounts.mockImplementation(
() => async (dispatch: Dispatch) => {
dispatch({ type: 'TYPE', payload: accounts });
return accounts;
},
);

Fuse.mockImplementation(() => ({
MockedFuse.mockImplementation(() => ({
search: jest.fn().mockReturnValue([
{
name: 'Saturn Test A',
address: '0x123',
},
]),
setCollection: jest.fn(),
list: [],
}));

const newMockStore = {
Expand Down
Loading

0 comments on commit 08c7333

Please sign in to comment.