From aa7f713972f0ca515027e9c3f493659a3210ece1 Mon Sep 17 00:00:00 2001 From: James Mealy Date: Wed, 29 May 2024 13:07:17 +0100 Subject: [PATCH] Add unit test, wrap grouping functions --- .../transactions/BulkTxListGroup/index.tsx | 4 +-- .../transactions/GroupedTxListItems/index.tsx | 2 +- src/components/transactions/TxList/index.tsx | 18 ++++-------- .../TxListItem/ExpandableTransactionItem.tsx | 6 ++-- .../transactions/TxSummary/index.test.tsx | 28 ++++++++++++------- .../transactions/TxSummary/index.tsx | 8 +++--- .../transactions/TxSummary/styles.module.css | 2 +- src/utils/transactions.ts | 3 +- src/utils/tx-list.ts | 9 ++++-- 9 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/components/transactions/BulkTxListGroup/index.tsx b/src/components/transactions/BulkTxListGroup/index.tsx index 10c67873e6..2c84f49218 100644 --- a/src/components/transactions/BulkTxListGroup/index.tsx +++ b/src/components/transactions/BulkTxListGroup/index.tsx @@ -22,7 +22,7 @@ const GroupedTxListItems = ({ - + Transactions executed in bulk @@ -37,7 +37,7 @@ const GroupedTxListItems = ({ : '' return ( - + {nonce} diff --git a/src/components/transactions/GroupedTxListItems/index.tsx b/src/components/transactions/GroupedTxListItems/index.tsx index 6bd632611d..424bcdcc89 100644 --- a/src/components/transactions/GroupedTxListItems/index.tsx +++ b/src/components/transactions/GroupedTxListItems/index.tsx @@ -45,7 +45,7 @@ const TxGroup = ({ groupedListItems }: { groupedListItems: Transaction[] }): Rea key={tx.transaction.id} className={replacedTxIds.includes(tx.transaction.id) ? css.willBeReplaced : undefined} > - + ))} diff --git a/src/components/transactions/TxList/index.tsx b/src/components/transactions/TxList/index.tsx index 1d668b17c4..7b58541425 100644 --- a/src/components/transactions/TxList/index.tsx +++ b/src/components/transactions/TxList/index.tsx @@ -1,6 +1,6 @@ import GroupedTxListItems from '@/components/transactions/GroupedTxListItems' import BulkTxListGroup from '@/components/transactions//BulkTxListGroup' -import { groupBulkTxs, groupConflictingTxs } from '@/utils/tx-list' +import { groupTxs } from '@/utils/tx-list' import { Box } from '@mui/material' import type { Transaction, TransactionDetails, TransactionListPage } from '@safe-global/safe-gateway-typescript-sdk' import type { ReactElement, ReactNode } from 'react' @@ -17,13 +17,6 @@ type TxListProps = { items: TransactionListPage['results'] } -// const isConflictGroup = (group: Transaction[]) => { -// const nonceList = group -// .map((item) => item.transaction.executionInfo) -// .filter(isMultisigExecutionInfo) -// .map((info) => info.nonce) -// return uniq(nonceList).length === 1 -// } const getBulkGroupTxHash = (group: Transaction[], txHashes: Record) => { const hashList = group.map((item) => { const txId = item.transaction.id @@ -39,7 +32,7 @@ export const TxListGrid = ({ children }: { children: ReactNode }): ReactElement const TxList = ({ items }: TxListProps): ReactElement => { const chainId = useChainId() - const [txHashes] = useAsync(async () => { + const [txHashesById] = useAsync(async () => { const transactions = items.filter(isTransactionListItem) return await getTxDetailsWithBackoff(transactions, chainId).then((txDetailsList) => { return txDetailsList.reduce((accumulator: Record, txDetails: TransactionDetails) => { @@ -51,15 +44,14 @@ const TxList = ({ items }: TxListProps): ReactElement => { }) }, [chainId, items]) - const groupedByConflicts = useMemo(() => groupConflictingTxs(items), [items]) - const groupedByBulks = useMemo(() => groupBulkTxs(groupedByConflicts, txHashes), [groupedByConflicts, txHashes]) + const groupedTransactions = useMemo(() => groupTxs(items, txHashesById), [items, txHashesById]) - const transactions = groupedByBulks.map((item, index) => { + const transactions = groupedTransactions.map((item, index) => { if (!Array.isArray(item)) { return } - const bulkTransactionHash = txHashes && getBulkGroupTxHash(item, txHashes) + const bulkTransactionHash = txHashesById && getBulkGroupTxHash(item, txHashesById) if (bulkTransactionHash) { return } diff --git a/src/components/transactions/TxListItem/ExpandableTransactionItem.tsx b/src/components/transactions/TxListItem/ExpandableTransactionItem.tsx index 76a4f94f22..f94fb2b358 100644 --- a/src/components/transactions/TxListItem/ExpandableTransactionItem.tsx +++ b/src/components/transactions/TxListItem/ExpandableTransactionItem.tsx @@ -12,14 +12,14 @@ import classNames from 'classnames' import { trackEvent, TX_LIST_EVENTS } from '@/services/analytics' type ExpandableTransactionItemProps = { - isGrouped?: boolean + isConflictGroup?: boolean isBulkGroup?: boolean item: Transaction txDetails?: TransactionDetails } export const ExpandableTransactionItem = ({ - isGrouped = false, + isConflictGroup = false, isBulkGroup = false, item, txDetails, @@ -58,7 +58,7 @@ export const ExpandableTransactionItem = ({ }, }} > - + diff --git a/src/components/transactions/TxSummary/index.test.tsx b/src/components/transactions/TxSummary/index.test.tsx index f14dfa919a..84a1a719ef 100644 --- a/src/components/transactions/TxSummary/index.test.tsx +++ b/src/components/transactions/TxSummary/index.test.tsx @@ -54,64 +54,72 @@ const mockTransactionInHistory = { describe('TxSummary', () => { it('should display a nonce if transaction is not grouped', () => { - const { getByText } = render() + const { getByText } = render() expect(getByText('7')).toBeInTheDocument() }) it('should not display a nonce if transaction is grouped', () => { - const { queryByText } = render() + const { queryByText } = render() expect(queryByText('7')).not.toBeInTheDocument() }) it('should not display a nonce if there is no executionInfo', () => { - const { queryByText } = render() + const { queryByText } = render() + + expect(queryByText('7')).not.toBeInTheDocument() + }) + + it('should not display a nonce for items in bulk execution group', () => { + const { queryByText } = render( + , + ) expect(queryByText('7')).not.toBeInTheDocument() }) it('should display confirmations if transactions is in queue', () => { - const { getByText } = render() + const { getByText } = render() expect(getByText('1 out of 3')).toBeInTheDocument() }) it('should not display confirmations if transactions is already executed', () => { - const { queryByText } = render() + const { queryByText } = render() expect(queryByText('1 out of 3')).not.toBeInTheDocument() }) it('should not display confirmations if there is no executionInfo', () => { - const { queryByText } = render() + const { queryByText } = render() expect(queryByText('1 out of 3')).not.toBeInTheDocument() }) it('should display a Sign button if confirmations are missing', () => { - const { getByText } = render() + const { getByText } = render() expect(getByText('Confirm')).toBeInTheDocument() }) it('should display a status label if transaction is in queue and pending', () => { jest.spyOn(pending, 'default').mockReturnValue(true) - const { getByTestId } = render() + const { getByTestId } = render() expect(getByTestId('tx-status-label')).toBeInTheDocument() }) it('should display a status label if transaction is not in queue', () => { jest.spyOn(pending, 'default').mockReturnValue(true) - const { getByTestId } = render() + const { getByTestId } = render() expect(getByTestId('tx-status-label')).toBeInTheDocument() }) it('should not display a status label if transaction is in queue and not pending', () => { jest.spyOn(pending, 'default').mockReturnValue(false) - const { queryByTestId } = render() + const { queryByTestId } = render() expect(queryByTestId('tx-status-label')).not.toBeInTheDocument() }) diff --git a/src/components/transactions/TxSummary/index.tsx b/src/components/transactions/TxSummary/index.tsx index cd7f075b99..ef6afb60e5 100644 --- a/src/components/transactions/TxSummary/index.tsx +++ b/src/components/transactions/TxSummary/index.tsx @@ -20,12 +20,12 @@ import { FEATURES } from '@/utils/chains' import TxStatusLabel from '@/components/transactions/TxStatusLabel' type TxSummaryProps = { - isGrouped?: boolean + isConflictGroup?: boolean isBulkGroup?: boolean item: Transaction } -const TxSummary = ({ item, isGrouped, isBulkGroup }: TxSummaryProps): ReactElement => { +const TxSummary = ({ item, isConflictGroup, isBulkGroup }: TxSummaryProps): ReactElement => { const hasDefaultTokenlist = useHasFeature(FEATURES.DEFAULT_TOKENLIST) const tx = item.transaction @@ -41,13 +41,13 @@ const TxSummary = ({ item, isGrouped, isBulkGroup }: TxSummaryProps): ReactEleme data-testid="transaction-item" className={classNames(css.gridContainer, { [css.history]: !isQueue, - [css.grouped]: isGrouped, + [css.grouped]: isConflictGroup, [css.isBulkGroup]: isBulkGroup, [css.untrusted]: !isTrusted, })} id={tx.id} > - {nonce !== undefined && !isGrouped && !isBulkGroup && ( + {nonce !== undefined && !isConflictGroup && !isBulkGroup && ( {nonce} diff --git a/src/components/transactions/TxSummary/styles.module.css b/src/components/transactions/TxSummary/styles.module.css index 0b3be0c679..ba6019b748 100644 --- a/src/components/transactions/TxSummary/styles.module.css +++ b/src/components/transactions/TxSummary/styles.module.css @@ -28,7 +28,7 @@ grid-template-areas: 'nonce type info date status'; } -.gridContainer.grouped { +.gridContainer.conflictGroup { grid-template-columns: var(--grid-type) var(--grid-info) var(--grid-date) var(--grid-confirmations) var(--grid-status) var( --grid-actions ); diff --git a/src/utils/transactions.ts b/src/utils/transactions.ts index 72aca88ad6..1d7231201b 100644 --- a/src/utils/transactions.ts +++ b/src/utils/transactions.ts @@ -150,9 +150,8 @@ export const getTxsWithDetails = (txs: Transaction[], chainId: string) => { export const getTxDetailsWithBackoff = (txs: Transaction[], chainId: string) => { return Promise.all( txs.map(async (tx) => { - // return await getTransactionDetails(chainId, tx.transaction.id) return await backOff(() => getTransactionDetails(chainId, tx.transaction.id), { - numOfAttempts: 19, + numOfAttempts: 10, }) }), ) diff --git a/src/utils/tx-list.ts b/src/utils/tx-list.ts index 410d29f383..72d24cd5ca 100644 --- a/src/utils/tx-list.ts +++ b/src/utils/tx-list.ts @@ -7,10 +7,15 @@ import type { RecoveryQueueItem } from '@/features/recovery/services/recovery-st type GroupedTxs = Array +export const groupTxs = (list: TransactionListItem[], txHashes: Record | undefined) => { + const groupedByConflicts = _groupConflictingTxs(list) + return _groupBulkTxs(groupedByConflicts, txHashes) +} + /** * Group txs by conflict header */ -export const groupConflictingTxs = (list: TransactionListItem[]): GroupedTxs => { +const _groupConflictingTxs = (list: TransactionListItem[]): GroupedTxs => { return list .reduce((resultItems, item) => { if (isConflictHeaderListItem(item)) { @@ -36,7 +41,7 @@ export const groupConflictingTxs = (list: TransactionListItem[]): GroupedTxs => /** * Group txs by tx hash */ -export const groupBulkTxs = (list: GroupedTxs, txHashes: Record | undefined): GroupedTxs => { +const _groupBulkTxs = (list: GroupedTxs, txHashes: Record | undefined): GroupedTxs => { if (!txHashes) return list return list