From d26546a64947a01b34209f5e1d80ffacb255561d Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 14 May 2024 11:33:15 -0400 Subject: [PATCH 01/11] remove Banner --- src/containers/Header/Banner.tsx | 23 ------------- src/containers/Header/test/Banner.test.tsx | 38 ---------------------- 2 files changed, 61 deletions(-) delete mode 100644 src/containers/Header/Banner.tsx delete mode 100644 src/containers/Header/test/Banner.test.tsx diff --git a/src/containers/Header/Banner.tsx b/src/containers/Header/Banner.tsx deleted file mode 100644 index 09334deac..000000000 --- a/src/containers/Header/Banner.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { FC } from 'react' -import { connect } from 'react-redux' -import { useTranslation } from 'react-i18next' -import { Notification } from '../shared/components/Notification' - -const BannerInner: FC<{ messages: [[string, string]] }> = ({ messages }) => { - const { t } = useTranslation() - return ( -
- {messages.map((d) => ( - - ))} -
- ) -} - -export const Banner = connect((state: any) => { - const messages = [['balanceError', state.accountHeader.error]] - - return { - messages: messages.filter((d) => Boolean(d[1])) as [[string, string]], - } -})(BannerInner) diff --git a/src/containers/Header/test/Banner.test.tsx b/src/containers/Header/test/Banner.test.tsx deleted file mode 100644 index 95ba1a918..000000000 --- a/src/containers/Header/test/Banner.test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { mount } from 'enzyme' -import { I18nextProvider } from 'react-i18next' -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import { Provider } from 'react-redux' -import { initialState } from '../../../rootReducer' -import i18n from '../../../i18n/testConfig' -import { Banner } from '../Banner' - -describe('Banner component', () => { - const middlewares = [thunk] - const mockStore = configureMockStore(middlewares) - const createWrapper = (state = initialState) => { - const store = mockStore(state) - return mount( - - - - - , - ) - } - - it('renders without crashing', () => { - const wrapper = createWrapper() - wrapper.unmount() - }) - - it('renders with messages', () => { - const state = { - ...initialState, - } - - const wrapper = createWrapper(state) - expect(wrapper.find('.notification').length).toEqual(0) - wrapper.unmount() - }) -}) From c2408984c7f7ccbb69fe01c17a51390870fcdf25 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 14 May 2024 12:34:00 -0400 Subject: [PATCH 02/11] switch AccountHeader off of redux --- .../Accounts/AccountHeader/index.tsx | 171 +++++++++--------- src/containers/Accounts/index.tsx | 2 +- src/containers/Accounts/test/index.test.tsx | 2 +- src/containers/Header/index.tsx | 2 - src/containers/Token/index.tsx | 2 +- src/containers/Token/test/index.test.tsx | 2 +- src/rootReducer.js | 5 - 7 files changed, 89 insertions(+), 97 deletions(-) diff --git a/src/containers/Accounts/AccountHeader/index.tsx b/src/containers/Accounts/AccountHeader/index.tsx index 3c04aff64..f3a6740f2 100644 --- a/src/containers/Accounts/AccountHeader/index.tsx +++ b/src/containers/Accounts/AccountHeader/index.tsx @@ -1,18 +1,19 @@ import { useContext, useEffect } from 'react' import { Trans, useTranslation } from 'react-i18next' -import { connect } from 'react-redux' -import { bindActionCreators } from 'redux' -import { loadAccountState } from './actions' +import { useQuery } from 'react-query' +import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec' import { Loader } from '../../shared/components/Loader' import './styles.scss' import { BalanceSelector } from './BalanceSelector/BalanceSelector' import { Account } from '../../shared/components/Account' -import { localizeNumber } from '../../shared/utils' +import { BAD_REQUEST, localizeNumber } from '../../shared/utils' import SocketContext from '../../shared/SocketContext' import InfoIcon from '../../shared/images/info.svg' import { useLanguage } from '../../shared/hooks' import Currency from '../../shared/components/Currency' import DomainLink from '../../shared/components/DomainLink' +import { getAccountState } from '../../../rippled' +import { useAnalytics } from '../../shared/analytics' const CURRENCY_OPTIONS = { style: 'currency', @@ -24,70 +25,81 @@ const CURRENCY_OPTIONS = { interface AccountHeaderProps { onSetCurrencySelected: (currency: string) => void currencySelected: string - loading: boolean accountId: string - data: { - balances: { - XRP: number - } - paychannels: { - // eslint-disable-next-line camelcase - total_available: string - channels: any[] - } - escrows: { - totalIn: number - totalOut: number - } - signerList: { - signers: { - account: string - weight: number - }[] - quorum: number - maxSigners: number - } - info: { - reserve: number - sequence: number - ticketCount: number - domain: string - emailHash: string - flags: string[] - nftMinter: string - } - xAddress: { - classicAddress: string - tag: number | boolean - test: boolean - } - deleted: boolean - hasBridge: boolean +} + +interface AccountState { + balances: { + XRP: number + } + paychannels: { + // eslint-disable-next-line camelcase + total_available: number + channels: any[] + } + escrows: { + totalIn: number + totalOut: number + } + signerList: { + signers: { + account: string + weight: number + }[] + quorum: number + maxSigners: number } - actions: { - loadAccountState: typeof loadAccountState + info: { + reserve: number + sequence: number + ticketCount: number + domain: string + emailHash: string + flags: string[] + nftMinter: string } + xAddress: { + classicAddress: string + tag: number | boolean + test: boolean + } + deleted: boolean + hasBridge: boolean } -const AccountHeader = (props: AccountHeaderProps) => { +export const AccountHeader = ({ + accountId, + onSetCurrencySelected, + currencySelected, +}: AccountHeaderProps) => { const { t } = useTranslation() const rippledSocket = useContext(SocketContext) const language = useLanguage() + const { trackException, trackScreenLoaded } = useAnalytics() const { - accountId, - actions, - data, - onSetCurrencySelected, - currencySelected, - loading, - } = props - const { deleted } = data + data: accountState, + error, + isLoading, + } = useQuery(['accountState', accountId], async () => { + if (!isValidClassicAddress(accountId) && !isValidXAddress(accountId)) { + return Promise.reject(BAD_REQUEST) + } + + return getAccountState(accountId, rippledSocket).catch( + (transactionRequestError) => { + const status = transactionRequestError.code + trackException(`ledger ${accountId} --- ${JSON.stringify(error)}`) + return Promise.reject(status) + }, + ) + }) + useEffect(() => { - actions.loadAccountState(accountId, rippledSocket) - }, [accountId, actions, rippledSocket]) + trackScreenLoaded() + }, [trackScreenLoaded]) - function renderBalancesSelector() { + function renderBalancesSelector(data: AccountState) { const { balances = {} } = data return ( Object.keys(balances).length > 1 && ( @@ -102,7 +114,7 @@ const AccountHeader = (props: AccountHeaderProps) => { ) } - function renderPaymentChannels() { + function renderPaymentChannels(data: AccountState) { const { paychannels } = data return ( paychannels && ( @@ -127,7 +139,7 @@ const AccountHeader = (props: AccountHeaderProps) => { ) } - function renderEscrows() { + function renderEscrows(data: AccountState) { const { escrows } = data return ( escrows && ( @@ -152,7 +164,7 @@ const AccountHeader = (props: AccountHeaderProps) => { ) } - function renderSignerList() { + function renderSignerList(data: AccountState) { const { signerList } = data return ( signerList && ( @@ -183,7 +195,7 @@ const AccountHeader = (props: AccountHeaderProps) => { } // TODO: show X-address on 'classic' account pages - function renderExtendedAddress() { + function renderExtendedAddress(data: AccountState) { const { xAddress } = data // undefined when page has not yet finished loading let messageAboutTag: JSX.Element | string = '' @@ -238,7 +250,7 @@ const AccountHeader = (props: AccountHeaderProps) => { ) } - function renderInfo() { + function renderInfo(data: AccountState) { const { info } = data return ( info && ( @@ -298,8 +310,8 @@ const AccountHeader = (props: AccountHeaderProps) => { ) } - function renderHeaderContent() { - const { balances = {} } = data + function renderHeaderContent(data: AccountState) { + const { balances = {}, deleted } = data const balance = localizeNumber( balances[currencySelected] || 0.0, language, @@ -313,7 +325,7 @@ const AccountHeader = (props: AccountHeaderProps) => { return (
- {renderExtendedAddress()} + {renderExtendedAddress(data)}
{deleted ? (
@@ -333,22 +345,23 @@ const AccountHeader = (props: AccountHeaderProps) => {
{balance}
)} - {renderBalancesSelector()} + {renderBalancesSelector(data)}
- {renderInfo()} - {renderEscrows()} - {renderPaymentChannels()} + {renderInfo(data)} + {renderEscrows(data)} + {renderPaymentChannels(data)}
-
{renderSignerList()}
+
{renderSignerList(data)}
) } - const { xAddress, hasBridge } = data + const xAddress = accountState?.xAddress ?? false + const hasBridge = accountState?.hasBridge ?? false return (
@@ -359,23 +372,9 @@ const AccountHeader = (props: AccountHeaderProps) => {

{accountId}

- {loading ? : renderHeaderContent()} + {isLoading ?? } + {accountState != null && renderHeaderContent(accountState)}
) } - -export default connect( - (state: any) => ({ - loading: state.accountHeader.loading, - data: state.accountHeader.data, - }), - (dispatch) => ({ - actions: bindActionCreators( - { - loadAccountState, - }, - dispatch, - ), - }), -)(AccountHeader) diff --git a/src/containers/Accounts/index.tsx b/src/containers/Accounts/index.tsx index 8f6361d6b..59a10f297 100644 --- a/src/containers/Accounts/index.tsx +++ b/src/containers/Accounts/index.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' import { Helmet } from 'react-helmet-async' -import AccountHeader from './AccountHeader' +import { AccountHeader } from './AccountHeader' import { AccountTransactionTable } from './AccountTransactionTable' import './styles.scss' import { useAnalytics } from '../shared/analytics' diff --git a/src/containers/Accounts/test/index.test.tsx b/src/containers/Accounts/test/index.test.tsx index efd512f38..0b0a83657 100644 --- a/src/containers/Accounts/test/index.test.tsx +++ b/src/containers/Accounts/test/index.test.tsx @@ -6,7 +6,7 @@ import { Route } from 'react-router' import { initialState } from '../../../rootReducer' import i18n from '../../../i18n/testConfig' import { Accounts } from '../index' -import AccountHeader from '../AccountHeader' +import { AccountHeader } from '../AccountHeader' import { AccountTransactionTable } from '../AccountTransactionTable' import mockAccountState from './mockAccountState.json' import { QuickHarness } from '../../test/utils' diff --git a/src/containers/Header/index.tsx b/src/containers/Header/index.tsx index 5ee021570..ea5dd5a81 100644 --- a/src/containers/Header/index.tsx +++ b/src/containers/Header/index.tsx @@ -1,7 +1,6 @@ import { FC } from 'react' import classnames from 'classnames' -import { Banner } from './Banner' import { navigationConfig } from '../App/navigation' import { NavigationMenu } from './NavigationMenu' @@ -15,7 +14,6 @@ export const Header: FC<{ inNetwork?: boolean }> = ({ inNetwork = true }) => (
- ) diff --git a/src/containers/Token/index.tsx b/src/containers/Token/index.tsx index 09310ac75..527ba8960 100644 --- a/src/containers/Token/index.tsx +++ b/src/containers/Token/index.tsx @@ -93,5 +93,5 @@ const Token: FC<{ error: string }> = ({ error }) => { } export default connect((state: any) => ({ - error: state.accountHeader.status, + error: state.tokenHeader.status, }))(Token) diff --git a/src/containers/Token/test/index.test.tsx b/src/containers/Token/test/index.test.tsx index c2f749d62..24f9cc508 100644 --- a/src/containers/Token/test/index.test.tsx +++ b/src/containers/Token/test/index.test.tsx @@ -39,7 +39,7 @@ describe('Token container', () => { it('renders static parts', () => { const state = { ...initialState, - accountHeader: { + tokenHeader: { loading: false, error: null, data: mockAccountState, diff --git a/src/rootReducer.js b/src/rootReducer.js index 69ab09b9a..b13610c14 100644 --- a/src/rootReducer.js +++ b/src/rootReducer.js @@ -1,18 +1,13 @@ import { combineReducers } from 'redux' -import accountHeaderReducer, { - initialState as accountHeaderState, -} from './containers/Accounts/AccountHeader/reducer' import tokenHeaderReducer, { initialState as tokenHeaderState, } from './containers/Token/TokenHeader/reducer' export const initialState = { - accountHeader: accountHeaderState, tokenHeader: tokenHeaderState, } const rootReducer = combineReducers({ - accountHeader: accountHeaderReducer, tokenHeader: tokenHeaderReducer, }) From fdf9dc08ca2cced60bc233aa94219d3142ef368a Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 14 May 2024 12:39:28 -0400 Subject: [PATCH 03/11] remove redux files --- .../Accounts/AccountHeader/actionTypes.js | 4 -- .../Accounts/AccountHeader/actions.js | 42 ------------------- .../Accounts/AccountHeader/reducer.js | 33 --------------- 3 files changed, 79 deletions(-) delete mode 100644 src/containers/Accounts/AccountHeader/actionTypes.js delete mode 100644 src/containers/Accounts/AccountHeader/actions.js delete mode 100644 src/containers/Accounts/AccountHeader/reducer.js diff --git a/src/containers/Accounts/AccountHeader/actionTypes.js b/src/containers/Accounts/AccountHeader/actionTypes.js deleted file mode 100644 index c539d0ce4..000000000 --- a/src/containers/Accounts/AccountHeader/actionTypes.js +++ /dev/null @@ -1,4 +0,0 @@ -export const START_LOADING_ACCOUNT_STATE = 'START_LOADING_ACCOUNT_STATE' -export const FINISHED_LOADING_ACCOUNT_STATE = 'FINISHED_LOADING_ACCOUNT_STATE' -export const ACCOUNT_STATE_LOAD_SUCCESS = 'ACCOUNT_STATE_LOAD_SUCCESS' -export const ACCOUNT_STATE_LOAD_FAIL = 'ACCOUNT_STATE_LOAD_FAIL' diff --git a/src/containers/Accounts/AccountHeader/actions.js b/src/containers/Accounts/AccountHeader/actions.js deleted file mode 100644 index 61e0dc53b..000000000 --- a/src/containers/Accounts/AccountHeader/actions.js +++ /dev/null @@ -1,42 +0,0 @@ -import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec' -import { getAccountState } from '../../../rippled' -import { analytics } from '../../shared/analytics' -import { BAD_REQUEST } from '../../shared/utils' -import * as actionTypes from './actionTypes' - -export const loadAccountState = (accountId, rippledSocket) => (dispatch) => { - if (!isValidClassicAddress(accountId) && !isValidXAddress(accountId)) { - dispatch({ - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - status: BAD_REQUEST, - error: '', - }) - return Promise.resolve() - } - - dispatch({ - type: actionTypes.START_LOADING_ACCOUNT_STATE, - }) - return getAccountState(accountId, rippledSocket) - .then((data) => { - dispatch({ type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }) - dispatch({ - type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, - data, - }) - }) - .catch((error) => { - const status = error.code - analytics.trackException( - `getAccountState ${accountId} --- ${JSON.stringify(error)}`, - ) - dispatch({ type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }) - dispatch({ - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - error: status === 500 ? 'get_account_state_failed' : '', - status, - }) - }) -} - -export default loadAccountState diff --git a/src/containers/Accounts/AccountHeader/reducer.js b/src/containers/Accounts/AccountHeader/reducer.js deleted file mode 100644 index 5ed1273fb..000000000 --- a/src/containers/Accounts/AccountHeader/reducer.js +++ /dev/null @@ -1,33 +0,0 @@ -import * as actionTypes from './actionTypes' - -export const initialState = { - loading: false, - data: {}, - error: '', - status: null, -} - -// eslint-disable-next-line default-param-last -const accountReducer = (state = initialState, action) => { - switch (action.type) { - case actionTypes.START_LOADING_ACCOUNT_STATE: - return { ...state, loading: true } - case actionTypes.FINISHED_LOADING_ACCOUNT_STATE: - return { ...state, loading: false } - case actionTypes.ACCOUNT_STATE_LOAD_SUCCESS: - return { ...state, error: '', data: action.data } - case actionTypes.ACCOUNT_STATE_LOAD_FAIL: - return { - ...state, - error: action.error, - status: action.status, - data: state.data.length ? state.data : {}, - } - case 'persist/REHYDRATE': - return { ...initialState } - default: - return state - } -} - -export default accountReducer From b765f392b62dfa711046f7356bac61975edfe0c3 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 14 May 2024 12:53:45 -0400 Subject: [PATCH 04/11] clean up TS issues --- .../Accounts/AccountHeader/index.tsx | 45 ++----------- .../{accountState.js => accountState.ts} | 67 +++++++++++++++++-- src/rippled/lib/rippled.js | 4 +- 3 files changed, 66 insertions(+), 50 deletions(-) rename src/rippled/{accountState.js => accountState.ts} (73%) diff --git a/src/containers/Accounts/AccountHeader/index.tsx b/src/containers/Accounts/AccountHeader/index.tsx index f3a6740f2..f2b776bad 100644 --- a/src/containers/Accounts/AccountHeader/index.tsx +++ b/src/containers/Accounts/AccountHeader/index.tsx @@ -14,6 +14,7 @@ import Currency from '../../shared/components/Currency' import DomainLink from '../../shared/components/DomainLink' import { getAccountState } from '../../../rippled' import { useAnalytics } from '../../shared/analytics' +import { AccountState } from '../../../rippled/accountState' const CURRENCY_OPTIONS = { style: 'currency', @@ -28,45 +29,6 @@ interface AccountHeaderProps { accountId: string } -interface AccountState { - balances: { - XRP: number - } - paychannels: { - // eslint-disable-next-line camelcase - total_available: number - channels: any[] - } - escrows: { - totalIn: number - totalOut: number - } - signerList: { - signers: { - account: string - weight: number - }[] - quorum: number - maxSigners: number - } - info: { - reserve: number - sequence: number - ticketCount: number - domain: string - emailHash: string - flags: string[] - nftMinter: string - } - xAddress: { - classicAddress: string - tag: number | boolean - test: boolean - } - deleted: boolean - hasBridge: boolean -} - export const AccountHeader = ({ accountId, onSetCurrencySelected, @@ -81,7 +43,7 @@ export const AccountHeader = ({ data: accountState, error, isLoading, - } = useQuery(['accountState', accountId], async () => { + } = useQuery(['accountState', accountId], () => { if (!isValidClassicAddress(accountId) && !isValidXAddress(accountId)) { return Promise.reject(BAD_REQUEST) } @@ -362,6 +324,7 @@ export const AccountHeader = ({ const xAddress = accountState?.xAddress ?? false const hasBridge = accountState?.hasBridge ?? false + return (
@@ -372,7 +335,7 @@ export const AccountHeader = ({

{accountId}

- {isLoading ?? } + {isLoading && } {accountState != null && renderHeaderContent(accountState)}
diff --git a/src/rippled/accountState.js b/src/rippled/accountState.ts similarity index 73% rename from src/rippled/accountState.js rename to src/rippled/accountState.ts index 8a03d309d..122cb8fdc 100644 --- a/src/rippled/accountState.js +++ b/src/rippled/accountState.ts @@ -20,13 +20,61 @@ import { } from './lib/rippled' import logger from './lib/logger' import { formatAccountInfo, formatSignerList } from './lib/utils' +import type { ExplorerAmount } from '../containers/shared/types' +import type { ExplorerXrplClient } from '../containers/shared/SocketContext' + +interface XAddress { + classicAddress: string + tag: number | false + test: boolean +} + +export interface AccountState { + account: string + balances: { + XRP: number + } + paychannels?: { + // eslint-disable-next-line camelcase + total_available: number + channels: any[] + } + escrows?: { + totalIn: number + totalOut: number + } + signerList?: { + signers: { + account: string + weight: number + }[] + quorum: number + maxSigners: number + } + info: { + reserve: number + sequence?: number + ticketCount: number + domain?: string + emailHash?: string + flags: string[] + nftMinter?: string + } + xAddress?: { + classicAddress: string + tag: number | boolean + test: boolean + } + deleted: boolean + hasBridge: boolean +} const log = logger({ name: 'account balances' }) const formatBalances = (info, data) => { const balances = { XRP: Number(info.Balance) / 1000000 } const { assets = {}, obligations = {} } = data - const tokens = [] + const tokens: ExplorerAmount[] = [] Object.keys(obligations).forEach((currency) => { if (!balances[currency]) { @@ -56,11 +104,14 @@ const formatBalances = (info, data) => { tokens, } } -const getAccountState = (account, rippledSocket) => { +async function getAccountState( + account: string, + rippledSocket: ExplorerXrplClient, +): Promise { // TODO: Retrieve balances for untagged X-address only? or display notice/warning - let classicAddress - let decomposedAddress = null + let classicAddress: string + let decomposedAddress: XAddress | null = null try { if (!isValidClassicAddress(account) && !isValidXAddress(account)) { @@ -85,7 +136,7 @@ const getAccountState = (account, rippledSocket) => { } else { classicAddress = account } - } catch (error) { + } catch (error: any) { log.error(error.toString()) throw error } @@ -101,8 +152,7 @@ const getAccountState = (account, rippledSocket) => { getServerInfo(rippledSocket), getAccountBridges(rippledSocket, classicAddress), ]).then((data) => ({ - account: info.Account, - ledger_index: info.ledger_index, + account: info.Account as string, info: formatAccountInfo(info, data[3].info.validated_ledger), balances: data[0].balances, tokens: data[0].tokens, @@ -128,6 +178,9 @@ const getAccountState = (account, rippledSocket) => { account: classicAddress, deleted: true, xAddress: decomposedAddress || undefined, + balances: { XRP: 0 }, + hasBridge: false, + info: { reserve: 0, ticketCount: 0, flags: [] }, } } throw error diff --git a/src/rippled/lib/rippled.js b/src/rippled/lib/rippled.js index 598a57e63..723121ced 100644 --- a/src/rippled/lib/rippled.js +++ b/src/rippled/lib/rippled.js @@ -274,7 +274,7 @@ const getAccountPaychannels = async ( return getChannels(resp.marker) } - return null + return undefined }) await getChannels() @@ -287,7 +287,7 @@ const getAccountPaychannels = async ( channels, total_available: remaining / XRP_BASE, } - : null + : undefined } // get account escrows From 4ee54e9ecf7089430c112a5cd9def200d10d9e64 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 14 May 2024 13:06:05 -0400 Subject: [PATCH 05/11] convert tokenheader --- jest.config.js | 1 - .../Accounts/AccountHeader/index.tsx | 35 +++--- src/containers/Token/TokenHeader/index.tsx | 106 +++++++++--------- 3 files changed, 75 insertions(+), 67 deletions(-) diff --git a/jest.config.js b/jest.config.js index 51e0c3218..814361c41 100644 --- a/jest.config.js +++ b/jest.config.js @@ -27,7 +27,6 @@ module.exports = { '!src/i18n/*', '!src/setupTests.js', '!src/setupProxy.js', - '!src/rootReducer.js', '!src/registerServiceWorker.js', '!src/containers/shared/images/*', '!src/containers/test/*', diff --git a/src/containers/Accounts/AccountHeader/index.tsx b/src/containers/Accounts/AccountHeader/index.tsx index f2b776bad..7d929915c 100644 --- a/src/containers/Accounts/AccountHeader/index.tsx +++ b/src/containers/Accounts/AccountHeader/index.tsx @@ -39,23 +39,26 @@ export const AccountHeader = ({ const language = useLanguage() const { trackException, trackScreenLoaded } = useAnalytics() - const { - data: accountState, - error, - isLoading, - } = useQuery(['accountState', accountId], () => { - if (!isValidClassicAddress(accountId) && !isValidXAddress(accountId)) { - return Promise.reject(BAD_REQUEST) - } + const { data: accountState, isLoading } = useQuery( + ['accountState', accountId], + () => { + if (!isValidClassicAddress(accountId) && !isValidXAddress(accountId)) { + return Promise.reject(BAD_REQUEST) + } - return getAccountState(accountId, rippledSocket).catch( - (transactionRequestError) => { - const status = transactionRequestError.code - trackException(`ledger ${accountId} --- ${JSON.stringify(error)}`) - return Promise.reject(status) - }, - ) - }) + return getAccountState(accountId, rippledSocket).catch( + (transactionRequestError) => { + const status = transactionRequestError.code + trackException( + `ledger ${accountId} --- ${JSON.stringify( + transactionRequestError, + )}`, + ) + return Promise.reject(status) + }, + ) + }, + ) useEffect(() => { trackScreenLoaded() diff --git a/src/containers/Token/TokenHeader/index.tsx b/src/containers/Token/TokenHeader/index.tsx index ba1c4e5ea..24a148f09 100644 --- a/src/containers/Token/TokenHeader/index.tsx +++ b/src/containers/Token/TokenHeader/index.tsx @@ -1,11 +1,14 @@ import { useContext, useEffect } from 'react' import { useTranslation } from 'react-i18next' -import { connect } from 'react-redux' -import { bindActionCreators } from 'redux' -import { loadTokenState } from './actions' +import { useQuery } from 'react-query' +import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec' import { Loader } from '../../shared/components/Loader' import './styles.scss' -import { localizeNumber, formatLargeNumber } from '../../shared/utils' +import { + localizeNumber, + formatLargeNumber, + BAD_REQUEST, +} from '../../shared/utils' import SocketContext from '../../shared/SocketContext' import Currency from '../../shared/components/Currency' import { Account } from '../../shared/components/Account' @@ -14,6 +17,8 @@ import { TokenTableRow } from '../../shared/components/TokenTableRow' import { useLanguage } from '../../shared/hooks' import { LEDGER_ROUTE, TRANSACTION_ROUTE } from '../../App/routes' import { RouteLink } from '../../shared/routing' +import { getToken } from '../../../rippled' +import { useAnalytics } from '../../shared/analytics' const CURRENCY_OPTIONS = { style: 'currency', @@ -23,42 +28,55 @@ const CURRENCY_OPTIONS = { } interface TokenHeaderProps { - loading: boolean accountId: string currency: string - data: { - balance: string - reserve: number - sequence: number - rate: number - obligations: string - domain: string - emailHash: string - previousLedger: number - previousTxn: string - flags: string[] - } - actions: { - loadTokenState: typeof loadTokenState - } } -const TokenHeader = ({ - actions, - accountId, - currency, - data, - loading, -}: TokenHeaderProps) => { +interface TokenData { + balance: string + reserve: number + sequence: number + rate: number + obligations: string + domain?: string + emailHash?: string + previousLedger: number + previousTxn: string + flags: string[] +} + +const TokenHeader = ({ accountId, currency }: TokenHeaderProps) => { const language = useLanguage() const { t } = useTranslation() const rippledSocket = useContext(SocketContext) + const { trackException, trackScreenLoaded } = useAnalytics() + + const { data: tokenData, isLoading } = useQuery( + ['token', accountId, currency], + () => { + if (!isValidClassicAddress(accountId) && !isValidXAddress(accountId)) { + return Promise.reject(BAD_REQUEST) + } + + return getToken(currency, accountId, rippledSocket).catch( + (rippledError) => { + const status = rippledError.code + trackException( + `token ${currency}.${accountId} --- ${JSON.stringify( + rippledError, + )}`, + ) + return Promise.reject(status) + }, + ) + }, + ) useEffect(() => { - actions.loadTokenState(currency, accountId, rippledSocket) - }, [accountId, actions, currency, rippledSocket]) + trackScreenLoaded() + }, [trackScreenLoaded]) - const renderDetails = () => { + const renderDetails = (data: TokenData) => { const { domain, rate, emailHash, previousLedger, previousTxn } = data const prevTxn = previousTxn && previousTxn.replace(/(.{20})..+/, '$1...') @@ -107,7 +125,7 @@ const TokenHeader = ({ ) } - const renderSettings = () => { + const renderSettings = (data: TokenData) => { const { flags } = data const rippling = @@ -141,7 +159,7 @@ const TokenHeader = ({ ) } - const renderHeaderContent = () => { + const renderHeaderContent = (data: TokenData) => { const { balance, sequence, obligations, reserve } = data const currencyBalance = localizeNumber( parseInt(balance, 10) / 1000000 || 0.0, @@ -187,18 +205,18 @@ const TokenHeader = ({

{t('details')}

- {renderDetails()} + {renderDetails(data)}

{t('settings')}

- {renderSettings()} + {renderSettings(data)}
) } - const { emailHash } = data + const emailHash = tokenData?.emailHash return (
@@ -211,23 +229,11 @@ const TokenHeader = ({ )}
- {loading ? : renderHeaderContent()} + {isLoading && } + {tokenData != null && renderHeaderContent(tokenData)}
) } -export default connect( - (state: any) => ({ - loading: state.tokenHeader.loading, - data: state.tokenHeader.data, - }), - (dispatch) => ({ - actions: bindActionCreators( - { - loadTokenState, - }, - dispatch, - ), - }), -)(TokenHeader) +export default TokenHeader From 4dda4157b88c0b6a7a13fb8a9a058c039fa515db Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 14 May 2024 13:09:40 -0400 Subject: [PATCH 06/11] fix TS issues --- server/routes/v1/tokenDiscovery.js | 5 ++--- src/containers/Token/TokenHeader/index.tsx | 14 +----------- src/rippled/lib/utils.js | 1 - src/rippled/{token.js => token.ts} | 26 +++++++++++++++++----- 4 files changed, 23 insertions(+), 23 deletions(-) rename src/rippled/{token.js => token.ts} (71%) diff --git a/server/routes/v1/tokenDiscovery.js b/server/routes/v1/tokenDiscovery.js index 7448d4e09..8bf552a93 100644 --- a/server/routes/v1/tokenDiscovery.js +++ b/server/routes/v1/tokenDiscovery.js @@ -36,7 +36,7 @@ async function getAccountInfo(issuer, currencyCode) { const domain = info.Domain ? Buffer.from(info.Domain, 'hex').toString() : undefined - return { domain, gravatar: info.urlgravatar, obligations } + return { domain, obligations } } async function getExchangeRate(issuer, currencyCode) { @@ -101,11 +101,10 @@ async function getTokensList() { // eslint-disable-next-line no-await-in-loop -- okay here, helps run slower so we don't get rate limited const [accountInfo, exchangeRate] = await Promise.all(promises) - const { domain, gravatar, obligations } = accountInfo + const { domain, obligations } = accountInfo const newInfo = { ...rankedTokens[i], domain, - gravatar, obligations, exchangeRate, } diff --git a/src/containers/Token/TokenHeader/index.tsx b/src/containers/Token/TokenHeader/index.tsx index 24a148f09..488599352 100644 --- a/src/containers/Token/TokenHeader/index.tsx +++ b/src/containers/Token/TokenHeader/index.tsx @@ -19,6 +19,7 @@ import { LEDGER_ROUTE, TRANSACTION_ROUTE } from '../../App/routes' import { RouteLink } from '../../shared/routing' import { getToken } from '../../../rippled' import { useAnalytics } from '../../shared/analytics' +import { TokenData } from '../../../rippled/token' const CURRENCY_OPTIONS = { style: 'currency', @@ -32,19 +33,6 @@ interface TokenHeaderProps { currency: string } -interface TokenData { - balance: string - reserve: number - sequence: number - rate: number - obligations: string - domain?: string - emailHash?: string - previousLedger: number - previousTxn: string - flags: string[] -} - const TokenHeader = ({ accountId, currency }: TokenHeaderProps) => { const language = useLanguage() const { t } = useTranslation() diff --git a/src/rippled/lib/utils.js b/src/rippled/lib/utils.js index 2c95c4db4..a0a27261b 100644 --- a/src/rippled/lib/utils.js +++ b/src/rippled/lib/utils.js @@ -68,7 +68,6 @@ const formatAccountInfo = (info, serverInfoValidated) => ({ emailHash: info.EmailHash, flags: buildFlags(info.Flags, ACCOUNT_FLAGS), balance: info.Balance, - gravatar: info.urlgravatar, previousTxn: info.PreviousTxnID, previousLedger: info.PreviousTxnLgrSeq, nftMinter: info.NFTokenMinter, diff --git a/src/rippled/token.js b/src/rippled/token.ts similarity index 71% rename from src/rippled/token.js rename to src/rippled/token.ts index aedc188c2..4325b7ed2 100644 --- a/src/rippled/token.js +++ b/src/rippled/token.ts @@ -1,10 +1,28 @@ import logger from './lib/logger' import { formatAccountInfo } from './lib/utils' import { getBalances, getAccountInfo, getServerInfo } from './lib/rippled' +import type { ExplorerXrplClient } from '../containers/shared/SocketContext' const log = logger({ name: 'iou' }) -const getToken = async (currencyCode, issuer, rippledSocket) => { +export interface TokenData { + balance: string + reserve: number + sequence: number + rate?: number + obligations: string + domain?: string + emailHash?: string + previousLedger: number + previousTxn: string + flags: string[] +} + +async function getToken( + currencyCode: string, + issuer: string, + rippledSocket: ExplorerXrplClient, +): Promise { try { log.info('fetching account info from rippled') const accountInfo = await getAccountInfo(rippledSocket, issuer) @@ -19,7 +37,6 @@ const getToken = async (currencyCode, issuer, rippledSocket) => { } const { - name, reserve, sequence, rate, @@ -27,13 +44,11 @@ const getToken = async (currencyCode, issuer, rippledSocket) => { emailHash, balance, flags, - gravatar, previousTxn, previousLedger, } = formatAccountInfo(accountInfo, serverInfo.info.validated_ledger) return { - name, reserve, sequence, rate, @@ -41,12 +56,11 @@ const getToken = async (currencyCode, issuer, rippledSocket) => { emailHash, balance, flags, - gravatar, obligations, previousTxn, previousLedger, } - } catch (error) { + } catch (error: any) { log.error(error.toString()) throw error } From 7aa1572c5f3d52f1cf9909402cb83abc84462095 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 14 May 2024 13:18:59 -0400 Subject: [PATCH 07/11] remove redux --- package-lock.json | 265 +----------------- package.json | 7 - .../AccountAssetTab/AccountAssetTab.tsx | 7 +- .../AccountHeader/test/reducer.test.js | 79 ------ src/containers/Accounts/test/index.test.tsx | 4 +- src/containers/App/test/App.test.jsx | 1 - .../test/CustomNetworkHome.test.js | 1 - src/containers/Header/test/Header.test.tsx | 1 - src/containers/Ledgers/Legend.tsx | 1 - .../Ledgers/test/LedgersPage.test.js | 1 - .../Token/TokenHeader/actionTypes.js | 4 - src/containers/Token/TokenHeader/actions.js | 43 --- src/containers/Token/TokenHeader/reducer.js | 33 --- .../Token/TokenHeader/test/reducer.test.js | 79 ------ src/containers/Token/index.tsx | 5 +- src/containers/Token/test/index.test.tsx | 3 +- src/index.tsx | 25 +- src/rootReducer.js | 14 - 18 files changed, 21 insertions(+), 552 deletions(-) delete mode 100644 src/containers/Accounts/AccountHeader/test/reducer.test.js delete mode 100644 src/containers/Token/TokenHeader/actionTypes.js delete mode 100644 src/containers/Token/TokenHeader/actions.js delete mode 100644 src/containers/Token/TokenHeader/reducer.js delete mode 100644 src/containers/Token/TokenHeader/test/reducer.test.js delete mode 100644 src/rootReducer.js diff --git a/package-lock.json b/package-lock.json index 7b1f75f3a..ea240f89a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@google-cloud/bigquery": "^7.6.1", "@paystring/utils": "^2.0.0", - "@redux-devtools/extension": "^3.3.0", "@rollup/plugin-inject": "^5.0.5", "@vitejs/plugin-react": "^4.2.1", "@xrplf/isomorphic": "^1.0.0-beta.1", @@ -43,14 +42,10 @@ "react-helmet-async": "^2.0.4", "react-i18next": "^12.3.1", "react-query": "^3.39.3", - "react-redux": "^8.1.3", "react-router": "^6.12.1", "react-router-dom": "^6.18.0", "react18-json-view": "^0.2.7", "recharts": "^2.12.6", - "redux": "^5.0.1", - "redux-logger": "^3.0.6", - "redux-thunk": "^2.2.0", "ripple-address-codec": "^5.0.0-beta.1", "topojson-client": "^3.0.0", "usehooks-ts": "^2.9.1", @@ -72,7 +67,6 @@ "@types/node": "^18.19.31", "@types/react": "^17.0.39", "@types/react-dom": "^17.0.9", - "@types/react-redux": "^7.1.22", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^6.21.0", "babel-jest": "^29.7.0", @@ -99,7 +93,6 @@ "prettier": "^3.0.3", "react-error-overlay": "6.0.11", "react-test-renderer": "^17.0.2", - "redux-mock-store": "^1.5.1", "sass": "^1.76.0", "source-map-explorer": "^2.5.3", "stylelint": "^15.11.0", @@ -5425,18 +5418,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/@redux-devtools/extension": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@redux-devtools/extension/-/extension-3.3.0.tgz", - "integrity": "sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "immutable": "^4.3.4" - }, - "peerDependencies": { - "redux": "^3.1.0 || ^4.0.0 || ^5.0.0" - } - }, "node_modules/@remix-run/router": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.11.0.tgz", @@ -6021,14 +6002,6 @@ "@types/node": "*" } }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.1", - "license": "MIT", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.3", "dev": true, @@ -6112,10 +6085,12 @@ }, "node_modules/@types/prop-types": { "version": "15.7.4", + "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "17.0.39", + "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -6125,34 +6100,15 @@ }, "node_modules/@types/react-dom": { "version": "17.0.9", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-redux": { - "version": "7.1.22", "dev": true, "license": "MIT", "dependencies": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, - "node_modules/@types/react-redux/node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.9.2" + "@types/react": "*" } }, "node_modules/@types/scheduler": { "version": "0.16.2", + "dev": true, "license": "MIT" }, "node_modules/@types/semver": { @@ -6166,11 +6122,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" - }, "node_modules/@types/yargs": { "version": "13.0.11", "dev": true, @@ -9854,10 +9805,6 @@ "node": ">=8" } }, - "node_modules/deep-diff": { - "version": "0.3.8", - "license": "MIT" - }, "node_modules/deep-equal": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", @@ -13258,13 +13205,6 @@ "he": "bin/he" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, "node_modules/hosted-git-info": { "version": "2.8.9", "dev": true, @@ -13474,7 +13414,8 @@ "node_modules/immutable": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", - "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "devOptional": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -21082,11 +21023,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.istypedarray": { "version": "3.0.6", "dev": true, @@ -23244,49 +23180,6 @@ } } }, - "node_modules/react-redux": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", - "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", - "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4 || ^5.0.0-beta.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, "node_modules/react-router": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.18.0.tgz", @@ -23489,30 +23382,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/redux": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" - }, - "node_modules/redux-logger": { - "version": "3.0.6", - "license": "MIT", - "dependencies": { - "deep-diff": "^0.3.5" - } - }, - "node_modules/redux-mock-store": { - "version": "1.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash.isplainobject": "^4.0.6" - } - }, - "node_modules/redux-thunk": { - "version": "2.3.0", - "license": "MIT" - }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -26891,14 +26760,6 @@ "node": ">=0.10.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/usehooks-ts": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz", @@ -31601,15 +31462,6 @@ "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true }, - "@redux-devtools/extension": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@redux-devtools/extension/-/extension-3.3.0.tgz", - "integrity": "sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==", - "requires": { - "@babel/runtime": "^7.23.2", - "immutable": "^4.3.4" - } - }, "@remix-run/router": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.11.0.tgz", @@ -32007,13 +31859,6 @@ "@types/node": "*" } }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "dev": true @@ -32090,10 +31935,12 @@ "peer": true }, "@types/prop-types": { - "version": "15.7.4" + "version": "15.7.4", + "dev": true }, "@types/react": { "version": "17.0.39", + "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -32102,34 +31949,14 @@ }, "@types/react-dom": { "version": "17.0.9", - "devOptional": true, - "requires": { - "@types/react": "*" - } - }, - "@types/react-redux": { - "version": "7.1.22", "dev": true, "requires": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - }, - "dependencies": { - "redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dev": true, - "requires": { - "@babel/runtime": "^7.9.2" - } - } + "@types/react": "*" } }, "@types/scheduler": { - "version": "0.16.2" + "version": "0.16.2", + "dev": true }, "@types/semver": { "version": "7.5.0", @@ -32141,11 +31968,6 @@ "version": "1.0.1", "dev": true }, - "@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" - }, "@types/yargs": { "version": "13.0.11", "dev": true, @@ -34668,9 +34490,6 @@ "mimic-response": "^2.0.0" } }, - "deep-diff": { - "version": "0.3.8" - }, "deep-equal": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", @@ -37016,12 +36835,6 @@ "he": { "version": "1.2.0" }, - "hoist-non-react-statics": { - "version": "3.3.2", - "requires": { - "react-is": "^16.7.0" - } - }, "hosted-git-info": { "version": "2.8.9", "dev": true @@ -37160,7 +36973,8 @@ "immutable": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", - "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "devOptional": true }, "import-fresh": { "version": "3.3.0", @@ -42432,10 +42246,6 @@ "version": "4.5.0", "dev": true }, - "lodash.isplainobject": { - "version": "4.0.6", - "dev": true - }, "lodash.istypedarray": { "version": "3.0.6", "dev": true @@ -43822,26 +43632,6 @@ "match-sorter": "^6.0.2" } }, - "react-redux": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", - "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", - "requires": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "dependencies": { - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - } - } - }, "react-router": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.18.0.tgz", @@ -43980,27 +43770,6 @@ "strip-indent": "^4.0.0" } }, - "redux": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" - }, - "redux-logger": { - "version": "3.0.6", - "requires": { - "deep-diff": "^0.3.5" - } - }, - "redux-mock-store": { - "version": "1.5.4", - "dev": true, - "requires": { - "lodash.isplainobject": "^4.0.6" - } - }, - "redux-thunk": { - "version": "2.3.0" - }, "reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -46296,12 +46065,6 @@ "version": "3.1.1", "dev": true }, - "use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} - }, "usehooks-ts": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz", diff --git a/package.json b/package.json index 9a0de5711..25d38eecd 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "dependencies": { "@google-cloud/bigquery": "^7.6.1", "@paystring/utils": "^2.0.0", - "@redux-devtools/extension": "^3.3.0", "@rollup/plugin-inject": "^5.0.5", "@vitejs/plugin-react": "^4.2.1", "@xrplf/isomorphic": "^1.0.0-beta.1", @@ -38,14 +37,10 @@ "react-helmet-async": "^2.0.4", "react-i18next": "^12.3.1", "react-query": "^3.39.3", - "react-redux": "^8.1.3", "react-router": "^6.12.1", "react-router-dom": "^6.18.0", "react18-json-view": "^0.2.7", "recharts": "^2.12.6", - "redux": "^5.0.1", - "redux-logger": "^3.0.6", - "redux-thunk": "^2.2.0", "ripple-address-codec": "^5.0.0-beta.1", "topojson-client": "^3.0.0", "usehooks-ts": "^2.9.1", @@ -67,7 +62,6 @@ "@types/node": "^18.19.31", "@types/react": "^17.0.39", "@types/react-dom": "^17.0.9", - "@types/react-redux": "^7.1.22", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^6.21.0", "babel-jest": "^29.7.0", @@ -94,7 +88,6 @@ "prettier": "^3.0.3", "react-error-overlay": "6.0.11", "react-test-renderer": "^17.0.2", - "redux-mock-store": "^1.5.1", "sass": "^1.76.0", "source-map-explorer": "^2.5.3", "stylelint": "^15.11.0", diff --git a/src/containers/Accounts/AccountAssetTab/AccountAssetTab.tsx b/src/containers/Accounts/AccountAssetTab/AccountAssetTab.tsx index c58f6e6da..4acc366b1 100644 --- a/src/containers/Accounts/AccountAssetTab/AccountAssetTab.tsx +++ b/src/containers/Accounts/AccountAssetTab/AccountAssetTab.tsx @@ -1,6 +1,5 @@ import { ChangeEvent } from 'react' import { useTranslation } from 'react-i18next' -import { connect } from 'react-redux' import { useNavigate } from 'react-router' import { useRouteParams } from '../../shared/routing' import { AccountIssuedTokenTable } from '../AccountIssuedTokenTable' @@ -14,7 +13,7 @@ interface Props { const assetTypes = ['issued', 'nft'] -const AccountAssetTabDisconnected = ({ account }: Props) => { +export const AccountAssetTab = ({ account }: Props) => { const { id: accountId = '', assetType = assetTypes[0] } = useRouteParams(ACCOUNT_ROUTE) const navigate = useNavigate() @@ -57,7 +56,3 @@ const AccountAssetTabDisconnected = ({ account }: Props) => { ) } - -export const AccountAssetTab = connect((state: any) => ({ - account: state.accountHeader.data, -}))(AccountAssetTabDisconnected) diff --git a/src/containers/Accounts/AccountHeader/test/reducer.test.js b/src/containers/Accounts/AccountHeader/test/reducer.test.js deleted file mode 100644 index ceecc491f..000000000 --- a/src/containers/Accounts/AccountHeader/test/reducer.test.js +++ /dev/null @@ -1,79 +0,0 @@ -import * as actionTypes from '../actionTypes' -import reducer, { initialState } from '../reducer' - -describe('AccountHeader reducers', () => { - it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(initialState) - }) - - it('should handle START_LOADING_ACCOUNT_STATE', () => { - const nextState = { ...initialState, loading: true } - expect( - reducer(initialState, { type: actionTypes.START_LOADING_ACCOUNT_STATE }), - ).toEqual(nextState) - }) - - it('should handle FINISHED_LOADING_ACCOUNT_STATE', () => { - const nextState = { ...initialState, loading: false } - expect( - reducer(initialState, { - type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE, - }), - ).toEqual(nextState) - }) - - it('should handle ACCOUNT_STATE_LOAD_SUCCESS', () => { - const data = [['XRP', 123.456]] - const nextState = { ...initialState, data } - expect( - reducer(initialState, { - data, - type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, - }), - ).toEqual(nextState) - }) - - it('should handle ACCOUNT_STATE_LOAD_FAIL', () => { - const status = 500 - const error = 'error' - const nextState = { ...initialState, status, error } - expect( - reducer(initialState, { - status, - error, - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - }), - ).toEqual(nextState) - }) - - it('will not clear previous data on ACCOUNT_STATE_LOAD_FAIL', () => { - const data = [['XRP', 123.456]] - const error = 'error' - const status = 500 - const stateWithData = { ...initialState, data } - const nextState = { ...stateWithData, error, status } - expect( - reducer(stateWithData, { - status, - error, - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - }), - ).toEqual(nextState) - }) - - it('should clear data on rehydration', () => { - const error = 'error' - const status = 500 - const nextState = { ...initialState, error, status } - expect( - reducer(initialState, { - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - error, - status, - }), - ).toEqual(nextState) - expect(reducer(nextState, { type: 'persist/REHYDRATE' })).toEqual( - initialState, - ) - }) -}) diff --git a/src/containers/Accounts/test/index.test.tsx b/src/containers/Accounts/test/index.test.tsx index 0b0a83657..8c504f5f1 100644 --- a/src/containers/Accounts/test/index.test.tsx +++ b/src/containers/Accounts/test/index.test.tsx @@ -3,7 +3,6 @@ import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk' import { Provider } from 'react-redux' import { Route } from 'react-router' -import { initialState } from '../../../rootReducer' import i18n from '../../../i18n/testConfig' import { Accounts } from '../index' import { AccountHeader } from '../AccountHeader' @@ -18,7 +17,7 @@ describe('Account container', () => { const middlewares = [thunk] const mockStore = configureMockStore(middlewares) const createWrapper = (state = {}) => { - const store = mockStore({ ...initialState, ...state }) + const store = mockStore({ ...state }) return mount( { it('renders static parts', () => { const state = { - ...initialState, accountHeader: { loading: false, error: null, diff --git a/src/containers/App/test/App.test.jsx b/src/containers/App/test/App.test.jsx index 15674340b..3e0852600 100644 --- a/src/containers/App/test/App.test.jsx +++ b/src/containers/App/test/App.test.jsx @@ -6,7 +6,6 @@ import configureMockStore from 'redux-mock-store' import { Provider } from 'react-redux' import thunk from 'redux-thunk' import { XrplClient } from 'xrpl-client' -import { initialState } from '../../../rootReducer' import i18n from '../../../i18n/testConfig' import { AppWrapper } from '../index' import MockWsClient from '../../test/mockWsClient' diff --git a/src/containers/CustomNetworkHome/test/CustomNetworkHome.test.js b/src/containers/CustomNetworkHome/test/CustomNetworkHome.test.js index f57ae01c3..b4ad34ad8 100644 --- a/src/containers/CustomNetworkHome/test/CustomNetworkHome.test.js +++ b/src/containers/CustomNetworkHome/test/CustomNetworkHome.test.js @@ -2,7 +2,6 @@ import { mount } from 'enzyme' import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk' import { Provider } from 'react-redux' -import { initialState } from '../../../rootReducer' import i18n from '../../../i18n/testConfig' import SidechainHome from '../index' import MockWsClient from '../../test/mockWsClient' diff --git a/src/containers/Header/test/Header.test.tsx b/src/containers/Header/test/Header.test.tsx index c1c715fab..1510a2ba5 100644 --- a/src/containers/Header/test/Header.test.tsx +++ b/src/containers/Header/test/Header.test.tsx @@ -4,7 +4,6 @@ import { BrowserRouter as Router } from 'react-router-dom' import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk' import { Provider } from 'react-redux' -import { initialState } from '../../../rootReducer' import i18n from '../../../i18n/testConfigEnglish' import SocketContext from '../../shared/SocketContext' import MockWsClient from '../../test/mockWsClient' diff --git a/src/containers/Ledgers/Legend.tsx b/src/containers/Ledgers/Legend.tsx index d0b7e764f..eb22a8349 100644 --- a/src/containers/Ledgers/Legend.tsx +++ b/src/containers/Ledgers/Legend.tsx @@ -18,7 +18,6 @@ export const Legend = () => { useLocalStorage(LEGEND_STORAGE_KEY, false) const [hidden, setHidden] = useState(previousInteraction) - // TODO: use global variables when we update places using width from redux. // Show legend by default when on desktop sizes useEffect(() => { if (previousInteraction === false) { diff --git a/src/containers/Ledgers/test/LedgersPage.test.js b/src/containers/Ledgers/test/LedgersPage.test.js index 925372e07..befaaebb4 100644 --- a/src/containers/Ledgers/test/LedgersPage.test.js +++ b/src/containers/Ledgers/test/LedgersPage.test.js @@ -6,7 +6,6 @@ import thunk from 'redux-thunk' import { Provider } from 'react-redux' import i18n from '../../../i18n/testConfig' import { LedgersPage } from '../index' -import { initialState } from '../../../rootReducer' import SocketContext from '../../shared/SocketContext' import NetworkContext from '../../shared/NetworkContext' import BaseMockWsClient from '../../test/mockWsClient' diff --git a/src/containers/Token/TokenHeader/actionTypes.js b/src/containers/Token/TokenHeader/actionTypes.js deleted file mode 100644 index c539d0ce4..000000000 --- a/src/containers/Token/TokenHeader/actionTypes.js +++ /dev/null @@ -1,4 +0,0 @@ -export const START_LOADING_ACCOUNT_STATE = 'START_LOADING_ACCOUNT_STATE' -export const FINISHED_LOADING_ACCOUNT_STATE = 'FINISHED_LOADING_ACCOUNT_STATE' -export const ACCOUNT_STATE_LOAD_SUCCESS = 'ACCOUNT_STATE_LOAD_SUCCESS' -export const ACCOUNT_STATE_LOAD_FAIL = 'ACCOUNT_STATE_LOAD_FAIL' diff --git a/src/containers/Token/TokenHeader/actions.js b/src/containers/Token/TokenHeader/actions.js deleted file mode 100644 index 0d56b287d..000000000 --- a/src/containers/Token/TokenHeader/actions.js +++ /dev/null @@ -1,43 +0,0 @@ -import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec' -import { getToken } from '../../../rippled' -import { analytics } from '../../shared/analytics' -import { BAD_REQUEST } from '../../shared/utils' -import * as actionTypes from './actionTypes' - -export const loadTokenState = - (currency, accountId, rippledSocket) => (dispatch) => { - if (!isValidClassicAddress(accountId) && !isValidXAddress(accountId)) { - dispatch({ - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - status: BAD_REQUEST, - error: '', - }) - return Promise.resolve() - } - - dispatch({ - type: actionTypes.START_LOADING_ACCOUNT_STATE, - }) - return getToken(currency, accountId, rippledSocket) - .then((data) => { - dispatch({ type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }) - dispatch({ - type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, - data, - }) - }) - .catch((error) => { - const status = error.code - analytics.trackException( - `token ${currency}.${accountId} --- ${JSON.stringify(error)}`, - ) - dispatch({ type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }) - dispatch({ - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - error: status === 500 ? 'get_account_state_failed' : '', - status, - }) - }) - } - -export default loadTokenState diff --git a/src/containers/Token/TokenHeader/reducer.js b/src/containers/Token/TokenHeader/reducer.js deleted file mode 100644 index b4768d53b..000000000 --- a/src/containers/Token/TokenHeader/reducer.js +++ /dev/null @@ -1,33 +0,0 @@ -import * as actionTypes from './actionTypes' - -export const initialState = { - loading: false, - data: {}, - error: '', - status: null, -} - -// eslint-disable-next-line default-param-last -const tokenReducer = (state = initialState, action) => { - switch (action.type) { - case actionTypes.START_LOADING_ACCOUNT_STATE: - return { ...state, loading: true } - case actionTypes.FINISHED_LOADING_ACCOUNT_STATE: - return { ...state, loading: false } - case actionTypes.ACCOUNT_STATE_LOAD_SUCCESS: - return { ...state, error: '', data: action.data } - case actionTypes.ACCOUNT_STATE_LOAD_FAIL: - return { - ...state, - error: action.error, - status: action.status, - data: state.data.length ? state.data : {}, - } - case 'persist/REHYDRATE': - return { ...initialState } - default: - return state - } -} - -export default tokenReducer diff --git a/src/containers/Token/TokenHeader/test/reducer.test.js b/src/containers/Token/TokenHeader/test/reducer.test.js deleted file mode 100644 index ceecc491f..000000000 --- a/src/containers/Token/TokenHeader/test/reducer.test.js +++ /dev/null @@ -1,79 +0,0 @@ -import * as actionTypes from '../actionTypes' -import reducer, { initialState } from '../reducer' - -describe('AccountHeader reducers', () => { - it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(initialState) - }) - - it('should handle START_LOADING_ACCOUNT_STATE', () => { - const nextState = { ...initialState, loading: true } - expect( - reducer(initialState, { type: actionTypes.START_LOADING_ACCOUNT_STATE }), - ).toEqual(nextState) - }) - - it('should handle FINISHED_LOADING_ACCOUNT_STATE', () => { - const nextState = { ...initialState, loading: false } - expect( - reducer(initialState, { - type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE, - }), - ).toEqual(nextState) - }) - - it('should handle ACCOUNT_STATE_LOAD_SUCCESS', () => { - const data = [['XRP', 123.456]] - const nextState = { ...initialState, data } - expect( - reducer(initialState, { - data, - type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, - }), - ).toEqual(nextState) - }) - - it('should handle ACCOUNT_STATE_LOAD_FAIL', () => { - const status = 500 - const error = 'error' - const nextState = { ...initialState, status, error } - expect( - reducer(initialState, { - status, - error, - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - }), - ).toEqual(nextState) - }) - - it('will not clear previous data on ACCOUNT_STATE_LOAD_FAIL', () => { - const data = [['XRP', 123.456]] - const error = 'error' - const status = 500 - const stateWithData = { ...initialState, data } - const nextState = { ...stateWithData, error, status } - expect( - reducer(stateWithData, { - status, - error, - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - }), - ).toEqual(nextState) - }) - - it('should clear data on rehydration', () => { - const error = 'error' - const status = 500 - const nextState = { ...initialState, error, status } - expect( - reducer(initialState, { - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - error, - status, - }), - ).toEqual(nextState) - expect(reducer(nextState, { type: 'persist/REHYDRATE' })).toEqual( - initialState, - ) - }) -}) diff --git a/src/containers/Token/index.tsx b/src/containers/Token/index.tsx index 527ba8960..34cde9030 100644 --- a/src/containers/Token/index.tsx +++ b/src/containers/Token/index.tsx @@ -1,6 +1,5 @@ import { FC, PropsWithChildren, useEffect } from 'react' import { useTranslation } from 'react-i18next' -import { connect } from 'react-redux' import { Helmet } from 'react-helmet-async' import TokenHeader from './TokenHeader' @@ -92,6 +91,4 @@ const Token: FC<{ error: string }> = ({ error }) => { ) } -export default connect((state: any) => ({ - error: state.tokenHeader.status, -}))(Token) +export default Token diff --git a/src/containers/Token/test/index.test.tsx b/src/containers/Token/test/index.test.tsx index 24f9cc508..263a4082f 100644 --- a/src/containers/Token/test/index.test.tsx +++ b/src/containers/Token/test/index.test.tsx @@ -3,7 +3,6 @@ import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk' import { Provider } from 'react-redux' import { Route } from 'react-router-dom' -import { initialState } from '../../../rootReducer' import i18n from '../../../i18n/testConfig' import Token from '../index' import TokenHeader from '../TokenHeader' @@ -18,7 +17,7 @@ describe('Token container', () => { const middlewares = [thunk] const mockStore = configureMockStore(middlewares) const createWrapper = (state = {}) => { - const store = mockStore({ ...initialState, ...state }) + const store = mockStore({ ...state }) return mount( { ReactDOM.render( - - - - - + + + , document.getElementById('xrpl-explorer'), @@ -33,19 +22,11 @@ const renderApp = () => { const isDevelopment = process.env.NODE_ENV === 'development' -const middlewarePackages = [thunk] -let middleware = applyMiddleware(...middlewarePackages) if (isDevelopment) { localStorage.setItem('debug', 'xrpl-debug:*') - middlewarePackages.push(reduxLogger) - middleware = applyMiddleware(...middlewarePackages) - enhancers = composeWithDevTools(middleware) - store = createStore(rootReducer, enhancers) renderApp() } else { localStorage.removeItem('debug') - enhancers = compose(middleware) - store = createStore(rootReducer, enhancers) renderApp() } diff --git a/src/rootReducer.js b/src/rootReducer.js deleted file mode 100644 index b13610c14..000000000 --- a/src/rootReducer.js +++ /dev/null @@ -1,14 +0,0 @@ -import { combineReducers } from 'redux' -import tokenHeaderReducer, { - initialState as tokenHeaderState, -} from './containers/Token/TokenHeader/reducer' - -export const initialState = { - tokenHeader: tokenHeaderState, -} - -const rootReducer = combineReducers({ - tokenHeader: tokenHeaderReducer, -}) - -export default rootReducer From 6f51761df4d784f8964051ff7048be3d9c7bf002 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 15 May 2024 13:49:34 -0400 Subject: [PATCH 08/11] convert AccountHeader tests --- .../AccountHeader/test/AccountHeader.test.tsx | 282 ++++++++++++++++ .../AccountHeader/test/actions.test.js | 312 ------------------ .../test/AccountNFTtable.test.tsx | 6 - src/containers/Accounts/index.tsx | 2 +- 4 files changed, 283 insertions(+), 319 deletions(-) create mode 100644 src/containers/Accounts/AccountHeader/test/AccountHeader.test.tsx delete mode 100644 src/containers/Accounts/AccountHeader/test/actions.test.js diff --git a/src/containers/Accounts/AccountHeader/test/AccountHeader.test.tsx b/src/containers/Accounts/AccountHeader/test/AccountHeader.test.tsx new file mode 100644 index 000000000..c8370635b --- /dev/null +++ b/src/containers/Accounts/AccountHeader/test/AccountHeader.test.tsx @@ -0,0 +1,282 @@ +import { mount } from 'enzyme' +import { QueryClientProvider } from 'react-query' +import { I18nextProvider } from 'react-i18next' +import { BrowserRouter } from 'react-router-dom' +import { testQueryClient } from '../../../test/QueryClient' +import i18n from '../../../../i18n/testConfig' +import { AccountHeader } from '..' +import { getAccountState } from '../../../../rippled' +import Mock = jest.Mock +import { flushPromises } from '../../../test/utils' + +const TEST_ADDRESS = 'rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv' +const TEST_X_ADDRESS = 'XV3oNHx95sqdCkTDCBCVsVeuBmvh2dz5fTZvfw8UCcMVsfe' + +jest.mock('../../../../rippled', () => ({ + __esModule: true, + getAccountState: jest.fn(), +})) + +const mockedGetAccountState = getAccountState as Mock + +describe('AccountHeader Actions', () => { + const createWrapper = (account = TEST_ADDRESS) => + mount( + + + + + + + , + ) + + beforeEach(() => { + jest.resetModules() + }) + + it('successful account header', async () => { + mockedGetAccountState.mockImplementation(() => + Promise.resolve({ + account: TEST_ADDRESS, + ledger_index: 68990183, + info: { + sequence: 2148991, + ticketCount: undefined, + ownerCount: 0, + reserve: 10, + tick: undefined, + rate: undefined, + domain: undefined, + emailHash: undefined, + flags: [], + balance: '123456000', + nftMinter: undefined, + previousTxn: + '6B6F2CA1633A22247058E988372BA9EFFFC5BF10212230B67341CA32DC9D4A82', + previousLedger: 68990183, + }, + deleted: false, + balances: { XRP: 123.456 }, + signerList: undefined, + tokens: [], + escrows: undefined, + paychannels: null, + xAddress: undefined, + hasBridge: false, + }), + ) + + const wrapper = createWrapper() + await flushPromises() + wrapper.update() + + expect(wrapper.find('h1').text()).toBe(TEST_ADDRESS) + + wrapper.unmount() + }) + + it('account with tokens', async () => { + mockedGetAccountState.mockImplementation(() => + Promise.resolve({ + account: 'rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY', + ledger_index: 72338736, + info: { + sequence: 1227, + ticketCount: undefined, + ownerCount: 28, + reserve: 66, + tick: undefined, + rate: undefined, + domain: undefined, + emailHash: undefined, + flags: [], + balance: '1172875760329', + previousTxn: + '259A84CE4B3B09D5FBCAA133F62FC767CA2B57B3C64CF065F7546AA63D55E070', + previousLedger: 67657581, + }, + balances: { + '0158415500000000C1F76FF6ECB0BAC600000000': 3.692385398244198, + BTC: 1.075524263886059, + CHF: 0.7519685210971255, + CNY: 12.328638002, + DYM: 95.13258522535791, + EUR: 53.426387263174405, + GBP: 79.51188949705619, + JPY: 4986.30908732758, + USD: 936.8290046958887, + XAU: 3.419442510305086, + XRP: 1172875.760329, + }, + signerList: undefined, + tokens: [ + { + amount: 95.13258522535791, + currency: 'DYM', + issuer: 'rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E', + }, + { + amount: 20, + currency: 'USD', + issuer: 'rME7HanzUymzFvETpoLgAy5rvxGcKiLrYL', + }, + { + amount: 255.7836054268899, + currency: 'USD', + issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q', + }, + { + amount: 1.075524263886059, + currency: 'BTC', + issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q', + }, + { + amount: 12.328638002, + currency: 'CNY', + issuer: 'rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK', + }, + { + amount: 3.419442510305086, + currency: 'XAU', + issuer: 'rrh7rf1gV2pXAoqA8oYbpHd8TKv5ZQeo67', + }, + { + amount: 3.692385398244198, + currency: '0158415500000000C1F76FF6ECB0BAC600000000', + issuer: 'rrh7rf1gV2pXAoqA8oYbpHd8TKv5ZQeo67', + }, + { + amount: 0.7519685210971255, + currency: 'CHF', + issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', + }, + { + amount: 78.5098894970562, + currency: 'GBP', + issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', + }, + { + amount: 4986.30908732758, + currency: 'JPY', + issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', + }, + { + amount: 28.42638726317441, + currency: 'EUR', + issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', + }, + ], + escrows: undefined, + paychannels: null, + xAddress: undefined, + hasBridge: false, + deleted: false, + }), + ) + + const wrapper = createWrapper() + await flushPromises() + wrapper.update() + + expect(wrapper.find('h1').text()).toBe(TEST_ADDRESS) + expect(wrapper.find('.balance-selector-container')).toExist() + expect(wrapper.find('.balance .value').text()).toBe('\uE9001,172,875.76') + + wrapper.unmount() + }) + + it('should dispatch correct actions on successful loadAccountState for X-Address', async () => { + mockedGetAccountState.mockImplementation(() => + Promise.resolve({ + account: TEST_ADDRESS, + ledger_index: 68990183, + info: { + sequence: 2148991, + ticketCount: undefined, + ownerCount: 0, + reserve: 10, + tick: undefined, + rate: undefined, + domain: undefined, + emailHash: undefined, + flags: [], + balance: '123456000', + nftMinter: undefined, + previousTxn: + '6B6F2CA1633A22247058E988372BA9EFFFC5BF10212230B67341CA32DC9D4A82', + previousLedger: 68990183, + }, + deleted: false, + balances: { XRP: 123.456 }, + signerList: undefined, + tokens: [], + escrows: undefined, + hasBridge: false, + paychannels: null, + xAddress: { + classicAddress: TEST_ADDRESS, + tag: 0, + test: false, + }, + }), + ) + + const wrapper = createWrapper(TEST_X_ADDRESS) + await flushPromises() + wrapper.update() + + expect(wrapper.find('h1').text()).toBe(TEST_X_ADDRESS) + + wrapper.unmount() + }) + + it('server error', async () => { + mockedGetAccountState.mockImplementation(() => {}) + + const wrapper = createWrapper() + await flushPromises() + wrapper.update() + + expect(wrapper.find('h1').text()).toBe(TEST_ADDRESS) + expect(wrapper.find('.header-container')).not.toExist() + + wrapper.unmount() + }) + + it('should dispatch correct actions on invalid address', async () => { + const wrapper = createWrapper('ZZZ') + await flushPromises() + wrapper.update() + + expect(wrapper.find('h1').text()).toBe('ZZZ') + expect(wrapper.find('.header-container')).not.toExist() + + wrapper.unmount() + }) + + it('deleted account', async () => { + mockedGetAccountState.mockImplementation(() => + Promise.resolve({ + account: TEST_ADDRESS, + deleted: true, + xAddress: undefined, + }), + ) + + const wrapper = createWrapper() + await flushPromises() + wrapper.update() + + expect(wrapper.find('h1').text()).toBe(TEST_ADDRESS) + expect(wrapper.find('.warning').find('.account-deleted-text').text()).toBe( + 'Account Deleted', + ) + + wrapper.unmount() + }) +}) diff --git a/src/containers/Accounts/AccountHeader/test/actions.test.js b/src/containers/Accounts/AccountHeader/test/actions.test.js deleted file mode 100644 index 797787a05..000000000 --- a/src/containers/Accounts/AccountHeader/test/actions.test.js +++ /dev/null @@ -1,312 +0,0 @@ -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import * as actions from '../actions' -import * as actionTypes from '../actionTypes' -import { initialState } from '../reducer' -import { NOT_FOUND, BAD_REQUEST, SERVER_ERROR } from '../../../shared/utils' -import rippledResponses from './rippledResponses.json' -import accountDeletedTransactions from './accountDeletedTransactions.json' -import actNotFound from '../../../Token/TokenHeader/test/actNotFound.json' -import actWithTokens from './accountWithTokens.json' -import MockWsClient from '../../../test/mockWsClient' - -const TEST_ADDRESS = 'rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv' -const TEST_X_ADDRESS = 'XV3oNHx95sqdCkTDCBCVsVeuBmvh2dz5fTZvfw8UCcMVsfe' - -describe('AccountHeader Actions', () => { - const middlewares = [thunk] - const mockStore = configureMockStore(middlewares) - let client - beforeEach(() => { - client = new MockWsClient() - }) - - afterEach(() => { - client.close() - }) - - it('should dispatch correct actions on successful loadAccountState', () => { - client.addResponses(rippledResponses) - const expectedData = { - account: 'rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv', - ledger_index: 68990183, - info: { - sequence: 2148991, - ticketCount: undefined, - ownerCount: 0, - reserve: 10, - tick: undefined, - rate: undefined, - domain: undefined, - emailHash: undefined, - flags: [], - balance: '123456000', - nftMinter: undefined, - previousTxn: - '6B6F2CA1633A22247058E988372BA9EFFFC5BF10212230B67341CA32DC9D4A82', - previousLedger: 68990183, - }, - deleted: false, - balances: { XRP: 123.456 }, - signerList: undefined, - tokens: [], - escrows: undefined, - paychannels: null, - xAddress: undefined, - hasBridge: false, - } - const expectedActions = [ - { type: actionTypes.START_LOADING_ACCOUNT_STATE }, - { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }, - { type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, data: expectedData }, - ] - const store = mockStore({ news: initialState }) - - return store - .dispatch(actions.loadAccountState(TEST_ADDRESS, client)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on account with tokens', () => { - client.addResponses(actWithTokens) - const expectedData = { - account: 'rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY', - ledger_index: 72338736, - info: { - sequence: 1227, - ticketCount: undefined, - ownerCount: 28, - reserve: 66, - tick: undefined, - rate: undefined, - domain: undefined, - emailHash: undefined, - flags: [], - balance: '1172875760329', - previousTxn: - '259A84CE4B3B09D5FBCAA133F62FC767CA2B57B3C64CF065F7546AA63D55E070', - previousLedger: 67657581, - }, - balances: { - '0158415500000000C1F76FF6ECB0BAC600000000': 3.692385398244198, - BTC: 1.075524263886059, - CHF: 0.7519685210971255, - CNY: 12.328638002, - DYM: 95.13258522535791, - EUR: 53.426387263174405, - GBP: 79.51188949705619, - JPY: 4986.30908732758, - USD: 936.8290046958887, - XAU: 3.419442510305086, - XRP: 1172875.760329, - }, - signerList: undefined, - tokens: [ - { - amount: 95.13258522535791, - currency: 'DYM', - issuer: 'rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E', - }, - { - amount: 20, - currency: 'USD', - issuer: 'rME7HanzUymzFvETpoLgAy5rvxGcKiLrYL', - }, - { - amount: 255.7836054268899, - currency: 'USD', - issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q', - }, - { - amount: 1.075524263886059, - currency: 'BTC', - issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q', - }, - { - amount: 12.328638002, - currency: 'CNY', - issuer: 'rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK', - }, - { - amount: 3.419442510305086, - currency: 'XAU', - issuer: 'rrh7rf1gV2pXAoqA8oYbpHd8TKv5ZQeo67', - }, - { - amount: 3.692385398244198, - currency: '0158415500000000C1F76FF6ECB0BAC600000000', - issuer: 'rrh7rf1gV2pXAoqA8oYbpHd8TKv5ZQeo67', - }, - { - amount: 0.7519685210971255, - currency: 'CHF', - issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', - }, - { - amount: 78.5098894970562, - currency: 'GBP', - issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', - }, - { - amount: 4986.30908732758, - currency: 'JPY', - issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', - }, - { - amount: 28.42638726317441, - currency: 'EUR', - issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', - }, - ], - escrows: undefined, - paychannels: null, - xAddress: undefined, - hasBridge: false, - deleted: false, - } - const expectedActions = [ - { type: actionTypes.START_LOADING_ACCOUNT_STATE }, - { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }, - { type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, data: expectedData }, - ] - const store = mockStore({ news: initialState }) - - return store - .dispatch(actions.loadAccountState(TEST_ADDRESS, client)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on successful loadAccountState for X-Address', () => { - client.addResponses(rippledResponses) - const expectedData = { - account: 'rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv', - ledger_index: 68990183, - info: { - sequence: 2148991, - ticketCount: undefined, - ownerCount: 0, - reserve: 10, - tick: undefined, - rate: undefined, - domain: undefined, - emailHash: undefined, - flags: [], - balance: '123456000', - nftMinter: undefined, - previousTxn: - '6B6F2CA1633A22247058E988372BA9EFFFC5BF10212230B67341CA32DC9D4A82', - previousLedger: 68990183, - }, - deleted: false, - balances: { XRP: 123.456 }, - signerList: undefined, - tokens: [], - escrows: undefined, - hasBridge: false, - paychannels: null, - xAddress: { - classicAddress: 'rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv', - tag: 0, - test: false, - }, - } - const expectedActions = [ - { type: actionTypes.START_LOADING_ACCOUNT_STATE }, - { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }, - { type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, data: expectedData }, - ] - const store = mockStore({ news: initialState }) - return store - .dispatch(actions.loadAccountState(TEST_X_ADDRESS, client)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on server error', () => { - client.setReturnError() - const expectedActions = [ - { type: actionTypes.START_LOADING_ACCOUNT_STATE }, - { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }, - { - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - status: SERVER_ERROR, - error: 'get_account_state_failed', - }, - ] - const store = mockStore({ news: initialState }) - - return store - .dispatch(actions.loadAccountState(TEST_ADDRESS, client)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on address not found', () => { - const expectedActions = [ - { type: actionTypes.START_LOADING_ACCOUNT_STATE }, - { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }, - { - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - status: NOT_FOUND, - error: '', - }, - ] - client.addResponse('account_info', { result: actNotFound }) - client.addResponse('account_tx', { result: actNotFound }) - const store = mockStore({ news: initialState }) - return store - .dispatch(actions.loadAccountState(TEST_ADDRESS, client)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on invalid address', () => { - const expectedActions = [ - { - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - status: BAD_REQUEST, - error: '', - }, - ] - const store = mockStore({ news: initialState }) - store.dispatch(actions.loadAccountState('ZZZ', client)).then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on a deleted account', () => { - client.addResponses(accountDeletedTransactions) - - const expectedActions = [ - { - type: 'START_LOADING_ACCOUNT_STATE', - }, - { - type: 'FINISHED_LOADING_ACCOUNT_STATE', - }, - { - type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, - data: { - account: 'r35jYntLwkrbc3edisgavDbEdNRSKgcQE6', - deleted: true, - xAddress: undefined, - }, - }, - ] - const store = mockStore({ news: initialState }) - store - .dispatch( - actions.loadAccountState('r35jYntLwkrbc3edisgavDbEdNRSKgcQE6', client), - ) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) -}) diff --git a/src/containers/Accounts/AccountNFTTable/test/AccountNFTtable.test.tsx b/src/containers/Accounts/AccountNFTTable/test/AccountNFTtable.test.tsx index 1ba9a9609..6b9ed48e0 100644 --- a/src/containers/Accounts/AccountNFTTable/test/AccountNFTtable.test.tsx +++ b/src/containers/Accounts/AccountNFTTable/test/AccountNFTtable.test.tsx @@ -52,8 +52,6 @@ describe('AccountNFTTable component', () => { }) it('should render a table of nfts', async () => { - mockedGetAccountNFTs.mockReset() - mockedGetAccountNFTs.mockImplementation(() => Promise.resolve(data)) const wrapper = createWrapper() @@ -66,8 +64,6 @@ describe('AccountNFTTable component', () => { }) it('should handle load more', async () => { - mockedGetAccountNFTs.mockReset() - mockedGetAccountNFTs.mockImplementation(() => Promise.resolve({ ...data, @@ -92,8 +88,6 @@ describe('AccountNFTTable component', () => { }) it(`should handle no results`, async () => { - mockedGetAccountNFTs.mockReset() - mockedGetAccountNFTs.mockImplementation(() => Promise.resolve({ account: 'rnuweigWrt8Jp1gBmKJT6VLxrVMSJSuu6G', diff --git a/src/containers/Accounts/index.tsx b/src/containers/Accounts/index.tsx index 59a10f297..dfdbd539d 100644 --- a/src/containers/Accounts/index.tsx +++ b/src/containers/Accounts/index.tsx @@ -44,7 +44,7 @@ export const Accounts = () => { hasTokensColumn={false} /> )} - {tab === 'assets' && } + {tab === 'assets' && } )} From d52b18e76a96a4a34bf34def61c3c546ed4611fd Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 15 May 2024 14:02:37 -0400 Subject: [PATCH 09/11] fix TokenHeader tests --- .../AccountHeader/test/AccountHeader.test.tsx | 6 +- src/containers/Token/TokenHeader/index.tsx | 3 +- .../TokenHeader/test/TokenHeader.test.tsx | 89 +++++++++++++++ .../Token/TokenHeader/test/actions.test.js | 108 ------------------ 4 files changed, 94 insertions(+), 112 deletions(-) create mode 100644 src/containers/Token/TokenHeader/test/TokenHeader.test.tsx delete mode 100644 src/containers/Token/TokenHeader/test/actions.test.js diff --git a/src/containers/Accounts/AccountHeader/test/AccountHeader.test.tsx b/src/containers/Accounts/AccountHeader/test/AccountHeader.test.tsx index c8370635b..a5598e5ee 100644 --- a/src/containers/Accounts/AccountHeader/test/AccountHeader.test.tsx +++ b/src/containers/Accounts/AccountHeader/test/AccountHeader.test.tsx @@ -190,7 +190,7 @@ describe('AccountHeader Actions', () => { wrapper.unmount() }) - it('should dispatch correct actions on successful loadAccountState for X-Address', async () => { + it('X-Address', async () => { mockedGetAccountState.mockImplementation(() => Promise.resolve({ account: TEST_ADDRESS, @@ -236,7 +236,7 @@ describe('AccountHeader Actions', () => { }) it('server error', async () => { - mockedGetAccountState.mockImplementation(() => {}) + mockedGetAccountState.mockImplementation(() => Promise.reject()) const wrapper = createWrapper() await flushPromises() @@ -248,7 +248,7 @@ describe('AccountHeader Actions', () => { wrapper.unmount() }) - it('should dispatch correct actions on invalid address', async () => { + it('invalid address', async () => { const wrapper = createWrapper('ZZZ') await flushPromises() wrapper.update() diff --git a/src/containers/Token/TokenHeader/index.tsx b/src/containers/Token/TokenHeader/index.tsx index 488599352..a7679d0c7 100644 --- a/src/containers/Token/TokenHeader/index.tsx +++ b/src/containers/Token/TokenHeader/index.tsx @@ -20,6 +20,7 @@ import { RouteLink } from '../../shared/routing' import { getToken } from '../../../rippled' import { useAnalytics } from '../../shared/analytics' import { TokenData } from '../../../rippled/token' +import { XRP_BASE } from '../../shared/transactionUtils' const CURRENCY_OPTIONS = { style: 'currency', @@ -150,7 +151,7 @@ const TokenHeader = ({ accountId, currency }: TokenHeaderProps) => { const renderHeaderContent = (data: TokenData) => { const { balance, sequence, obligations, reserve } = data const currencyBalance = localizeNumber( - parseInt(balance, 10) / 1000000 || 0.0, + parseInt(balance, 10) / XRP_BASE || 0.0, language, CURRENCY_OPTIONS, ) diff --git a/src/containers/Token/TokenHeader/test/TokenHeader.test.tsx b/src/containers/Token/TokenHeader/test/TokenHeader.test.tsx new file mode 100644 index 000000000..c7865ddfe --- /dev/null +++ b/src/containers/Token/TokenHeader/test/TokenHeader.test.tsx @@ -0,0 +1,89 @@ +import { mount } from 'enzyme' +import { QueryClientProvider } from 'react-query' +import { I18nextProvider } from 'react-i18next' +import { BrowserRouter } from 'react-router-dom' +import { testQueryClient } from '../../../test/QueryClient' +import i18n from '../../../../i18n/testConfig' +import TokenHeader from '..' +import { getToken } from '../../../../rippled' +import Mock = jest.Mock +import { flushPromises } from '../../../test/utils' + +const TEST_ADDRESS = 'rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv' +const TEST_CURRENCY = 'abc' + +jest.mock('../../../../rippled', () => ({ + __esModule: true, + getToken: jest.fn(), +})) + +const mockedGetToken = getToken as Mock + +describe('TokenHeader Actions', () => { + jest.setTimeout(10000) + + const createWrapper = (account = TEST_ADDRESS, currency = TEST_CURRENCY) => + mount( + + + + + + + , + ) + + it('successful token header', async () => { + mockedGetToken.mockImplementation(() => + Promise.resolve({ + obligations: '100', + sequence: 2148991, + reserve: 10, + rate: undefined, + domain: undefined, + emailHash: undefined, + flags: [], + balance: '123456000', + previousTxn: + '6B6F2CA1633A22247058E988372BA9EFFFC5BF10212230B67341CA32DC9D4A82', + previousLedger: 68990183, + }), + ) + + const wrapper = createWrapper() + await flushPromises() + wrapper.update() + + const values = wrapper.find('.info-container .values .value') + expect(values).toHaveLength(5) + expect(values.at(0)).toHaveText('\uE900123.456') + expect(values.at(1)).toHaveText('\uE90010.00') + expect(values.at(2)).toHaveText('2148991') + expect(values.at(3)).toHaveText(TEST_ADDRESS) + expect(values.at(4)).toHaveText('100.0000') + + wrapper.unmount() + }) + + it('server error', async () => { + mockedGetToken.mockImplementation(() => Promise.reject()) + + const wrapper = createWrapper() + await flushPromises() + wrapper.update() + + expect(wrapper.find('.header-container')).not.toExist() + + wrapper.unmount() + }) + + it('invalid ripple address', async () => { + const wrapper = createWrapper('ZZZ', undefined) + await flushPromises() + wrapper.update() + + expect(wrapper.find('.header-container')).not.toExist() + + wrapper.unmount() + }) +}) diff --git a/src/containers/Token/TokenHeader/test/actions.test.js b/src/containers/Token/TokenHeader/test/actions.test.js deleted file mode 100644 index bfae5b48a..000000000 --- a/src/containers/Token/TokenHeader/test/actions.test.js +++ /dev/null @@ -1,108 +0,0 @@ -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import * as actions from '../actions' -import * as actionTypes from '../actionTypes' -import { initialState } from '../reducer' -import { NOT_FOUND, BAD_REQUEST, SERVER_ERROR } from '../../../shared/utils' -import rippledResponses from './rippledResponses.json' -import actNotFound from './actNotFound.json' -import MockWsClient from '../../../test/mockWsClient' - -const TEST_ADDRESS = 'rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv' -const TEST_CURRENCY = 'abc' - -describe('TokenHeader Actions', () => { - jest.setTimeout(10000) - - const middlewares = [thunk] - const mockStore = configureMockStore(middlewares) - let client - beforeEach(() => { - client = new MockWsClient() - }) - - afterEach(() => { - client.close() - }) - - it('should dispatch correct actions on successful loadTokenState', () => { - client.addResponses(rippledResponses) - const expectedData = { - name: undefined, - obligations: '100', - sequence: 2148991, - reserve: 10, - rate: undefined, - domain: undefined, - emailHash: undefined, - flags: [], - balance: '123456000', - previousTxn: - '6B6F2CA1633A22247058E988372BA9EFFFC5BF10212230B67341CA32DC9D4A82', - previousLedger: 68990183, - } - const expectedActions = [ - { type: actionTypes.START_LOADING_ACCOUNT_STATE }, - { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }, - { type: actionTypes.ACCOUNT_STATE_LOAD_SUCCESS, data: expectedData }, - ] - const store = mockStore({ news: initialState }) - return store - .dispatch(actions.loadTokenState(TEST_CURRENCY, TEST_ADDRESS, client)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on server error', () => { - client.setReturnError() - const expectedActions = [ - { type: actionTypes.START_LOADING_ACCOUNT_STATE }, - { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }, - { - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - status: SERVER_ERROR, - error: 'get_account_state_failed', - }, - ] - const store = mockStore({ news: initialState }) - return store - .dispatch(actions.loadTokenState(TEST_CURRENCY, TEST_ADDRESS, client)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on ripple address not found', () => { - client.addResponse('account_info', { result: actNotFound }) - const expectedActions = [ - { type: actionTypes.START_LOADING_ACCOUNT_STATE }, - { type: actionTypes.FINISHED_LOADING_ACCOUNT_STATE }, - { - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - status: NOT_FOUND, - error: '', - }, - ] - const store = mockStore({ news: initialState }) - return store - .dispatch(actions.loadTokenState(TEST_CURRENCY, TEST_ADDRESS, client)) - .then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) - - it('should dispatch correct actions on invalid ripple address', () => { - const expectedActions = [ - { - type: actionTypes.ACCOUNT_STATE_LOAD_FAIL, - status: BAD_REQUEST, - error: '', - }, - ] - const store = mockStore({ news: initialState }) - store.dispatch(actions.loadTokenState('ZZZ', null, client)).then(() => { - expect(store.getActions()).toEqual(expectedActions) - }) - }) -}) From 52d550c40621186209b71d34f4aa8bf5436cb008 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 15 May 2024 14:22:23 -0400 Subject: [PATCH 10/11] fix other tests --- src/containers/Accounts/test/index.test.tsx | 61 ++++++++++--------- src/containers/App/test/App.test.jsx | 42 +++++++++---- .../test/CustomNetworkHome.test.js | 15 +---- src/containers/Header/test/Header.test.tsx | 20 ++---- .../Ledgers/test/LedgersPage.test.js | 32 ++++------ src/containers/Token/test/index.test.tsx | 59 +++++++++--------- 6 files changed, 111 insertions(+), 118 deletions(-) diff --git a/src/containers/Accounts/test/index.test.tsx b/src/containers/Accounts/test/index.test.tsx index 8c504f5f1..555cff680 100644 --- a/src/containers/Accounts/test/index.test.tsx +++ b/src/containers/Accounts/test/index.test.tsx @@ -1,51 +1,54 @@ import { mount } from 'enzyme' -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import { Provider } from 'react-redux' import { Route } from 'react-router' import i18n from '../../../i18n/testConfig' import { Accounts } from '../index' import { AccountHeader } from '../AccountHeader' import { AccountTransactionTable } from '../AccountTransactionTable' import mockAccountState from './mockAccountState.json' -import { QuickHarness } from '../../test/utils' +import { QuickHarness, flushPromises } from '../../test/utils' import { ACCOUNT_ROUTE } from '../../App/routes' +import { getAccountState } from '../../../rippled' +import Mock = jest.Mock + +jest.mock('../../../rippled', () => ({ + __esModule: true, + getAccountState: jest.fn(), + getAccountTransactions: jest.fn(() => []), +})) + +const mockedGetAccountState = getAccountState as Mock describe('Account container', () => { - const TEST_ACCOUNT_ID = 'rTEST_ACCOUNT' - - const middlewares = [thunk] - const mockStore = configureMockStore(middlewares) - const createWrapper = (state = {}) => { - const store = mockStore({ ...state }) - return mount( - - - } /> - - , + const TEST_ACCOUNT_ID = 'rncKvRcdDq9hVJpdLdTcKoxsS3NSkXsvfM' + + const createWrapper = () => + mount( + + } /> + , ) - } + + beforeEach(() => { + jest.resetModules() + }) it('renders without crashing', () => { const wrapper = createWrapper() wrapper.unmount() }) - it('renders static parts', () => { - const state = { - accountHeader: { - loading: false, - error: null, - data: mockAccountState, - }, - } + it('renders static parts', async () => { + mockedGetAccountState.mockImplementation(() => + Promise.resolve(mockAccountState), + ) - const wrapper = createWrapper(state) + const wrapper = createWrapper() + await flushPromises() wrapper.update() + expect(wrapper.find(AccountHeader).length).toBe(1) expect(wrapper.find(AccountTransactionTable).length).toBe(1) wrapper.find('.balance-selector button').simulate('click') diff --git a/src/containers/App/test/App.test.jsx b/src/containers/App/test/App.test.jsx index 3e0852600..7bf139280 100644 --- a/src/containers/App/test/App.test.jsx +++ b/src/containers/App/test/App.test.jsx @@ -2,9 +2,6 @@ import { mount } from 'enzyme' import moxios from 'moxios' import { MemoryRouter } from 'react-router' import { I18nextProvider } from 'react-i18next' -import configureMockStore from 'redux-mock-store' -import { Provider } from 'react-redux' -import thunk from 'redux-thunk' import { XrplClient } from 'xrpl-client' import i18n from '../../../i18n/testConfig' import { AppWrapper } from '../index' @@ -69,7 +66,6 @@ const mockXrplClient = XrplClient const mockGetAccountInfo = getAccountInfo describe('App container', () => { - const mockStore = configureMockStore([thunk]) const createWrapper = ( path = '/', localNetworks = [], @@ -88,15 +84,12 @@ describe('App container', () => { ) } - const store = mockStore(initialState) return mount( - - - - - - - , + + + + + , ) } @@ -269,6 +262,12 @@ describe('App container', () => { event: 'screen_view', network: 'mainnet', }, + { + page_path: '/accounts/rKV8HEL3vLc6q9waTiJcewdRdSFyx67QFb#ssss', + page_title: 'xrpl_explorer | rKV8HEL3vLc6...', + event: 'screen_view', + network: 'mainnet', + }, ]) }) }) @@ -305,6 +304,12 @@ describe('App container', () => { event: 'screen_view', network: 'mainnet', }, + { + page_path: '/accounts/r35jYntLwkrbc3edisgavDbEdNRSKgcQE6#ssss', + page_title: `xrpl_explorer | r35jYntLwkrb...`, + event: 'screen_view', + network: 'mainnet', + }, ]) expect(mockGetAccountInfo).toBeCalledWith( expect.anything(), @@ -326,6 +331,13 @@ describe('App container', () => { event: 'screen_view', network: 'mainnet', }, + { + page_path: + '/accounts/XVVFXHFdehYhofb7XRWeJYV6kjTEwboaHpB9S1ruYMsuXcG#ssss', + page_title: `xrpl_explorer | XVVFXHFdehYh...`, + event: 'screen_view', + network: 'mainnet', + }, ]) expect(mockGetAccountInfo).toBeCalledWith( expect.anything(), @@ -386,6 +398,12 @@ describe('App container', () => { event: 'screen_view', network: 'mainnet', }, + { + page_path: '/accounts/rKV8HEL3vLc6q9waTiJcewdRdSFyx67QFb#ssss', + page_title: 'xrpl_explorer | rKV8HEL3vLc6...', + event: 'screen_view', + network: 'mainnet', + }, ]) }) }) diff --git a/src/containers/CustomNetworkHome/test/CustomNetworkHome.test.js b/src/containers/CustomNetworkHome/test/CustomNetworkHome.test.js index b4ad34ad8..3e22b08ca 100644 --- a/src/containers/CustomNetworkHome/test/CustomNetworkHome.test.js +++ b/src/containers/CustomNetworkHome/test/CustomNetworkHome.test.js @@ -1,7 +1,4 @@ import { mount } from 'enzyme' -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import { Provider } from 'react-redux' import i18n from '../../../i18n/testConfig' import SidechainHome from '../index' import MockWsClient from '../../test/mockWsClient' @@ -12,9 +9,6 @@ describe('SidechainHome page', () => { let client let wrapper - const middlewares = [thunk] - const mockStore = configureMockStore(middlewares) - const createWrapper = (localNetworks = null) => { localStorage.removeItem(CUSTOM_NETWORKS_STORAGE_KEY) if (localNetworks) { @@ -24,13 +18,10 @@ describe('SidechainHome page', () => { ) } - const store = mockStore(initialState) return mount( - - - - - , + + + , ) } diff --git a/src/containers/Header/test/Header.test.tsx b/src/containers/Header/test/Header.test.tsx index 1510a2ba5..dc1d68684 100644 --- a/src/containers/Header/test/Header.test.tsx +++ b/src/containers/Header/test/Header.test.tsx @@ -1,9 +1,6 @@ import { mount } from 'enzyme' import { I18nextProvider } from 'react-i18next' import { BrowserRouter as Router } from 'react-router-dom' -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import { Provider } from 'react-redux' import i18n from '../../../i18n/testConfigEnglish' import SocketContext from '../../shared/SocketContext' import MockWsClient from '../../test/mockWsClient' @@ -11,23 +8,16 @@ import { Header } from '../index' describe('Header component', () => { let client - // Redux setup required for - const middlewares = [thunk] - const mockStore = configureMockStore(middlewares) - const createWrapper = () => { - const store = mockStore({ ...initialState }) - return mount( + const createWrapper = () => + mount( - - -
- - + +
+ , ) - } beforeEach(() => { client = new MockWsClient() diff --git a/src/containers/Ledgers/test/LedgersPage.test.js b/src/containers/Ledgers/test/LedgersPage.test.js index befaaebb4..adfc2aeca 100644 --- a/src/containers/Ledgers/test/LedgersPage.test.js +++ b/src/containers/Ledgers/test/LedgersPage.test.js @@ -1,9 +1,6 @@ import { mount } from 'enzyme' import moxios from 'moxios' import WS from 'jest-websocket-mock' -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import { Provider } from 'react-redux' import i18n from '../../../i18n/testConfig' import { LedgersPage } from '../index' import SocketContext from '../../shared/SocketContext' @@ -79,25 +76,18 @@ const WS_URL = 'ws://localhost:1234' describe('Ledgers Page container', () => { let server let client - const middlewares = [thunk] - const mockStore = configureMockStore(middlewares) - const createWrapper = (props = { network: 'main', path: '/' }) => { - const store = mockStore({ ...initialState }) - - return mount( - - - - - - - - - - - , + const createWrapper = (props = { network: 'main', path: '/' }) => + mount( + + + + + + + + + , ) - } const oldEnvs = process.env diff --git a/src/containers/Token/test/index.test.tsx b/src/containers/Token/test/index.test.tsx index 263a4082f..dd86514d9 100644 --- a/src/containers/Token/test/index.test.tsx +++ b/src/containers/Token/test/index.test.tsx @@ -1,51 +1,52 @@ import { mount } from 'enzyme' -import configureMockStore from 'redux-mock-store' -import thunk from 'redux-thunk' -import { Provider } from 'react-redux' import { Route } from 'react-router-dom' import i18n from '../../../i18n/testConfig' import Token from '../index' import TokenHeader from '../TokenHeader' import { TokenTransactionTable } from '../TokenTransactionTable' import mockAccountState from '../../Accounts/test/mockAccountState.json' -import { QuickHarness } from '../../test/utils' +import { QuickHarness, flushPromises } from '../../test/utils' import { TOKEN_ROUTE } from '../../App/routes' +import { getToken } from '../../../rippled' +import Mock = jest.Mock + +jest.mock('../../../rippled', () => ({ + __esModule: true, + getToken: jest.fn(), +})) + +const mockedGetToken = getToken as Mock + describe('Token container', () => { const TEST_ACCOUNT_ID = 'rTEST_ACCOUNT' - const middlewares = [thunk] - const mockStore = configureMockStore(middlewares) - const createWrapper = (state = {}) => { - const store = mockStore({ ...state }) - return mount( - - - } /> - - , + const createWrapper = () => + mount( + + } /> + , ) - } + + beforeEach(() => { + jest.resetModules() + }) it('renders without crashing', () => { const wrapper = createWrapper() wrapper.unmount() }) - it('renders static parts', () => { - const state = { - ...initialState, - tokenHeader: { - loading: false, - error: null, - data: mockAccountState, - }, - } - - const wrapper = createWrapper(state) + it('renders static parts', async () => { + mockedGetToken.mockImplementation(() => Promise.resolve(mockAccountState)) + + const wrapper = createWrapper() + await flushPromises() + wrapper.update() + expect(wrapper.find(TokenHeader).length).toBe(1) expect(wrapper.find(TokenTransactionTable).length).toBe(1) wrapper.unmount() From eeb1a8204b1862b687345219e2c5ad7899dd2800 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 17 Dec 2024 18:00:23 -0800 Subject: [PATCH 11/11] fix TS issues --- src/containers/Token/TokenHeader/index.tsx | 4 ++-- src/rippled/token.ts | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/containers/Token/TokenHeader/index.tsx b/src/containers/Token/TokenHeader/index.tsx index 9138e1ea4..c22ba9e7c 100644 --- a/src/containers/Token/TokenHeader/index.tsx +++ b/src/containers/Token/TokenHeader/index.tsx @@ -165,11 +165,11 @@ export const TokenHeader = ({

{t('details')}

- {renderDetails(data)} + {renderDetails()}

{t('settings')}

- {renderSettings(data)} + {renderSettings()}
diff --git a/src/rippled/token.ts b/src/rippled/token.ts index 3ae3a5e9e..ab1adebd9 100644 --- a/src/rippled/token.ts +++ b/src/rippled/token.ts @@ -6,11 +6,9 @@ import type { ExplorerXrplClient } from '../containers/shared/SocketContext' const log = logger({ name: 'iou' }) export interface TokenData { - name: string balance: string reserve: number sequence: number - gravatar: string rate?: number obligations?: string domain?: string