From 519ba8963a0775f3d156fa034fcc4cdfeedb20dc Mon Sep 17 00:00:00 2001 From: eddie <66155195+just-toby@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:36:56 -0700 Subject: [PATCH] test: unit tests for parseRemote (#7359) --- .../__snapshots__/parseRemote.test.tsx.snap | 338 ++++++++++++++ .../Activity/fixtures/activity.ts | 441 ++++++++++++++++++ .../Activity/parseRemote.test.tsx | 126 +++++ src/graphql/data/util.tsx | 2 +- 4 files changed, 906 insertions(+), 1 deletion(-) create mode 100644 src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/parseRemote.test.tsx.snap create mode 100644 src/components/AccountDrawer/MiniPortfolio/Activity/fixtures/activity.ts create mode 100644 src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.test.tsx diff --git a/src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/parseRemote.test.tsx.snap b/src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/parseRemote.test.tsx.snap new file mode 100644 index 0000000000..421ba18d9c --- /dev/null +++ b/src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/parseRemote.test.tsx.snap @@ -0,0 +1,338 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`parseRemote parseRemoteActivities should parse NFT approval 1`] = ` +Object { + "chainId": 1, + "descriptor": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [], + "nonce": 12345, + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Unknown Approval", +} +`; + +exports[`parseRemote parseRemoteActivities should parse NFT approval for all 1`] = ` +Object { + "chainId": 1, + "descriptor": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [], + "nonce": 12345, + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Unknown Approval", +} +`; + +exports[`parseRemote parseRemoteActivities should parse NFT receive 1`] = ` +Object { + "chainId": 1, + "currencies": undefined, + "descriptor": "1 SomeCollectionName from ", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "imageUrl", + ], + "nonce": 12345, + "otherAccount": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Received", +} +`; + +exports[`parseRemote parseRemoteActivities should parse NFT transfer 1`] = ` +Object { + "chainId": 1, + "descriptor": "1 SomeCollectionName", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "imageUrl", + ], + "nonce": 12345, + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Minted", +} +`; + +exports[`parseRemote parseRemoteActivities should parse closed UniswapX order 1`] = ` +Object { + "chainId": 1, + "currencies": Array [ + Token { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "DAI", + "symbol": "DAI", + }, + Token { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "Wrapped Ether", + "symbol": "WETH", + }, + ], + "descriptor": "100 DAI for 200 WETH", + "from": "someOfferer", + "hash": "someHash", + "logos": Array [ + "someUrl", + "someUrl", + ], + "offchainOrderStatus": "expired", + "prefixIconSrc": "bolt.svg", + "status": "FAILED", + "statusMessage": "Your swap could not be fulfilled at this time. Please try again.", + "timestamp": 10000, + "title": "Swap expired", +} +`; + +exports[`parseRemote parseRemoteActivities should parse moonpay purchase 1`] = ` +Object { + "chainId": 1, + "currencies": Array [ + Token { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "Wrapped Ether", + "symbol": "WETH", + }, + ], + "descriptor": "100 WETH for 100", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "moonpay.svg", + ], + "nonce": 12345, + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Purchased", +} +`; + +exports[`parseRemote parseRemoteActivities should parse nft purchase 1`] = ` +Object { + "chainId": 1, + "descriptor": "1 SomeCollectionName", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "imageUrl", + ], + "nonce": 12345, + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Bought", +} +`; + +exports[`parseRemote parseRemoteActivities should parse receive 1`] = ` +Object { + "chainId": 1, + "currencies": Array [ + Token { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "Wrapped Ether", + "symbol": "WETH", + }, + ], + "descriptor": "100 WETH from ", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "logoUrl", + ], + "nonce": 12345, + "otherAccount": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Received", +} +`; + +exports[`parseRemote parseRemoteActivities should parse remove liquidity 1`] = ` +Object { + "chainId": 1, + "currencies": Array [ + Token { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "Wrapped Ether", + "symbol": "WETH", + }, + Token { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "DAI", + "symbol": "DAI", + }, + ], + "descriptor": "100 WETH and 100 DAI", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "logoUrl", + "logoUrl", + ], + "nonce": 12345, + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Removed Liquidity", +} +`; + +exports[`parseRemote parseRemoteActivities should parse send 1`] = ` +Object { + "chainId": 1, + "currencies": Array [ + Token { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "DAI", + "symbol": "DAI", + }, + ], + "descriptor": "100 DAI to ", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "logoUrl", + ], + "nonce": 12345, + "otherAccount": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Sent", +} +`; + +exports[`parseRemote parseRemoteActivities should parse swap 1`] = ` +Object { + "chainId": 1, + "currencies": Array [ + Token { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "DAI", + "symbol": "DAI", + }, + Token { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "Wrapped Ether", + "symbol": "WETH", + }, + ], + "descriptor": "100 DAI for 100 WETH", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "logoUrl", + ], + "nonce": 12345, + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Swapped", +} +`; + +exports[`parseRemote parseRemoteActivities should parse swap order 1`] = ` +Object { + "chainId": 1, + "currencies": Array [ + Token { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "DAI", + "symbol": "DAI", + }, + Token { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "Wrapped Ether", + "symbol": "WETH", + }, + ], + "descriptor": "100 DAI for 100 WETH", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "logoUrl", + ], + "nonce": 12345, + "prefixIconSrc": "bolt.svg", + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Swapped", +} +`; + +exports[`parseRemote parseRemoteActivities should parse token approval 1`] = ` +Object { + "chainId": 1, + "currencies": Array [ + Token { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "chainId": 1, + "decimals": 18, + "isNative": false, + "isToken": true, + "name": "DAI", + "symbol": "DAI", + }, + ], + "descriptor": "DAI", + "from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3", + "hash": "someHash", + "logos": Array [ + "logoUrl", + ], + "nonce": 12345, + "status": "CONFIRMED", + "timestamp": 10000, + "title": "Approved", +} +`; diff --git a/src/components/AccountDrawer/MiniPortfolio/Activity/fixtures/activity.ts b/src/components/AccountDrawer/MiniPortfolio/Activity/fixtures/activity.ts new file mode 100644 index 0000000000..d722349392 --- /dev/null +++ b/src/components/AccountDrawer/MiniPortfolio/Activity/fixtures/activity.ts @@ -0,0 +1,441 @@ +import { ChainId, NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, WETH9 } from '@uniswap/sdk-core' +import { DAI } from 'constants/tokens' +import { + AssetActivityPartsFragment, + Chain, + Currency, + NftStandard, + SwapOrderStatus, + TokenStandard, + TransactionDirection, + TransactionStatus, + TransactionType, +} from 'graphql/data/__generated__/types-and-hooks' + +import { MOONPAY_SENDER_ADDRESSES } from '../../constants' + +const MockOrderTimestamp = 10000 +const MockRecipientAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' +const MockSenderAddress = '0x50EC05ADe8280758E2077fcBC08D878D4aef79C3' + +const mockAssetActivityPartsFragment = { + __typename: 'AssetActivity', + id: 'activityId', + timestamp: MockOrderTimestamp, + chain: Chain.Ethereum, + details: { + __typename: 'SwapOrderDetails', + id: 'detailsId', + offerer: 'offererId', + hash: 'someHash', + inputTokenQuantity: '100', + outputTokenQuantity: '200', + orderStatus: SwapOrderStatus.Open, + inputToken: { + __typename: 'Token', + id: 'tokenId', + chain: Chain.Ethereum, + standard: TokenStandard.Erc20, + }, + outputToken: { + __typename: 'Token', + id: 'tokenId', + chain: Chain.Ethereum, + standard: TokenStandard.Erc20, + }, + }, +} + +const mockSwapOrderDetailsPartsFragment = { + __typename: 'SwapOrderDetails', + id: 'someId', + offerer: 'someOfferer', + hash: 'someHash', + inputTokenQuantity: '100', + outputTokenQuantity: '200', + orderStatus: SwapOrderStatus.Open, + inputToken: { + __typename: 'Token', + id: DAI.address, + name: 'DAI', + symbol: DAI.symbol, + address: DAI.address, + decimals: 18, + chain: Chain.Ethereum, + standard: TokenStandard.Erc20, + project: { + __typename: 'TokenProject', + id: 'projectId', + isSpam: false, + logo: { + __typename: 'Image', + id: 'imageId', + url: 'someUrl', + }, + }, + }, + outputToken: { + __typename: 'Token', + id: WETH9[1].address, + name: 'Wrapped Ether', + symbol: 'WETH', + address: WETH9[1].address, + decimals: 18, + chain: Chain.Ethereum, + standard: TokenStandard.Erc20, + project: { + __typename: 'TokenProject', + id: 'projectId', + isSpam: false, + logo: { + __typename: 'Image', + id: 'imageId', + url: 'someUrl', + }, + }, + }, +} + +const mockNftApprovalPartsFragment = { + __typename: 'NftApproval', + id: 'approvalId', + nftStandard: NftStandard.Erc721, // Replace with actual enum value + approvedAddress: '0xApprovedAddress', + asset: { + __typename: 'NftAsset', + id: 'assetId', + name: 'SomeNftName', + tokenId: 'tokenId123', + nftContract: { + __typename: 'NftContract', + id: 'nftContractId', + chain: Chain.Ethereum, // Replace with actual enum value + address: '0xContractAddress', + }, + image: { + __typename: 'Image', + id: 'imageId', + url: 'imageUrl', + }, + collection: { + __typename: 'NftCollection', + id: 'collectionId', + name: 'SomeCollectionName', + }, + }, +} + +const mockNftApproveForAllPartsFragment = { + __typename: 'NftApproveForAll', + id: 'approveForAllId', + nftStandard: NftStandard.Erc721, // Replace with actual enum value + operatorAddress: '0xOperatorAddress', + approved: true, + asset: { + __typename: 'NftAsset', + id: 'assetId', + name: 'SomeNftName', + tokenId: 'tokenId123', + nftContract: { + __typename: 'NftContract', + id: 'nftContractId', + chain: Chain.Ethereum, // Replace with actual enum value + address: '0xContractAddress', + }, + image: { + __typename: 'Image', + id: 'imageId', + url: 'imageUrl', + }, + collection: { + __typename: 'NftCollection', + id: 'collectionId', + name: 'SomeCollectionName', + }, + }, +} + +const mockNftTransferPartsFragment = { + __typename: 'NftTransfer', + id: 'transferId', + nftStandard: NftStandard.Erc721, + sender: MockSenderAddress, + recipient: MockRecipientAddress, + direction: TransactionDirection.Out, + asset: { + __typename: 'NftAsset', + id: 'assetId', + name: 'SomeNftName', + tokenId: 'tokenId123', + nftContract: { + __typename: 'NftContract', + id: 'nftContractId', + chain: Chain.Ethereum, + address: '0xContractAddress', + }, + image: { + __typename: 'Image', + id: 'imageId', + url: 'imageUrl', + }, + collection: { + __typename: 'NftCollection', + id: 'collectionId', + name: 'SomeCollectionName', + }, + }, +} + +const mockTokenTransferOutPartsFragment = { + __typename: 'TokenTransfer', + id: 'tokenTransferId', + tokenStandard: TokenStandard.Erc20, + quantity: '100', + sender: MockSenderAddress, + recipient: MockRecipientAddress, + direction: TransactionDirection.Out, + asset: { + __typename: 'Token', + id: DAI.address, + name: 'DAI', + symbol: 'DAI', + address: DAI.address, + decimals: 18, + chain: Chain.Ethereum, + standard: TokenStandard.Erc20, + project: { + __typename: 'TokenProject', + id: 'projectId', + isSpam: false, + logo: { + __typename: 'Image', + id: 'logoId', + url: 'logoUrl', + }, + }, + }, + transactedValue: { + __typename: 'Amount', + id: 'amountId', + currency: Currency.Usd, + value: 100, + }, +} + +const mockTokenTransferInPartsFragment = { + __typename: 'TokenTransfer', + id: 'tokenTransferId', + tokenStandard: TokenStandard.Erc20, + quantity: '1', + sender: MockSenderAddress, + recipient: MockRecipientAddress, + direction: TransactionDirection.In, + asset: { + __typename: 'Token', + id: WETH9[1].address, + name: 'Wrapped Ether', + symbol: 'WETH', + address: WETH9[1].address, + decimals: 18, + chain: Chain.Ethereum, + standard: TokenStandard.Erc20, + project: { + __typename: 'TokenProject', + id: 'projectId', + isSpam: false, + logo: { + __typename: 'Image', + id: 'logoId', + url: 'logoUrl', + }, + }, + }, + transactedValue: { + __typename: 'Amount', + id: 'amountId', + currency: Currency.Usd, + value: 100, + }, +} + +const mockTokenApprovalPartsFragment = { + __typename: 'TokenApproval', + id: 'tokenApprovalId', + tokenStandard: TokenStandard.Erc20, + approvedAddress: DAI.address, + quantity: '50', + asset: { + __typename: 'Token', + id: 'tokenId', + name: 'DAI', + symbol: 'DAI', + address: DAI.address, + decimals: 18, + chain: Chain.Ethereum, + standard: TokenStandard.Erc20, + project: { + __typename: 'TokenProject', + id: 'projectId', + isSpam: false, + logo: { + __typename: 'Image', + id: 'logoId', + url: 'logoUrl', + }, + }, + }, +} + +export const MockOpenUniswapXOrder = { + ...mockAssetActivityPartsFragment, + details: mockSwapOrderDetailsPartsFragment, +} as AssetActivityPartsFragment + +export const MockClosedUniswapXOrder = { + ...mockAssetActivityPartsFragment, + details: { + ...mockSwapOrderDetailsPartsFragment, + orderStatus: SwapOrderStatus.Expired, + }, +} as AssetActivityPartsFragment + +const commonTransactionDetailsFields = { + __typename: 'TransactionDetails', + from: MockSenderAddress, + hash: 'someHash', + id: 'transactionId', + nonce: 12345, + status: TransactionStatus.Confirmed, + to: MockRecipientAddress, +} + +export const MockNFTApproval = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Approve, + assetChanges: [mockNftApprovalPartsFragment], + }, +} as AssetActivityPartsFragment + +export const MockNFTApprovalForAll = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Approve, + assetChanges: [mockNftApproveForAllPartsFragment], + }, +} as AssetActivityPartsFragment + +export const MockNFTTransfer = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Mint, + assetChanges: [mockNftTransferPartsFragment], + }, +} as AssetActivityPartsFragment + +export const MockTokenTransfer = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Swap, + assetChanges: [mockTokenTransferOutPartsFragment, mockTokenTransferInPartsFragment], + }, +} as AssetActivityPartsFragment + +export const MockSwapOrder = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.SwapOrder, + assetChanges: [mockTokenTransferOutPartsFragment, mockTokenTransferInPartsFragment], + }, +} as AssetActivityPartsFragment + +export const MockTokenApproval = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Approve, + assetChanges: [mockTokenApprovalPartsFragment], + }, +} as AssetActivityPartsFragment + +export const MockTokenSend = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Send, + assetChanges: [mockTokenTransferOutPartsFragment], + }, +} as AssetActivityPartsFragment + +export const MockTokenReceive = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Receive, + assetChanges: [mockTokenTransferInPartsFragment], + }, +} as AssetActivityPartsFragment + +export const MockRemoveLiquidity = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + to: NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[ChainId.MAINNET], + type: TransactionType.Receive, + assetChanges: [ + mockTokenTransferInPartsFragment, + { + ...mockTokenTransferOutPartsFragment, + direction: TransactionDirection.In, + }, + ], + }, +} as AssetActivityPartsFragment + +export const MockMoonpayPurchase = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Receive, + assetChanges: [ + { + ...mockTokenTransferInPartsFragment, + sender: MOONPAY_SENDER_ADDRESSES[0], + }, + ], + }, +} as AssetActivityPartsFragment + +export const MockNFTReceive = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Receive, + assetChanges: [ + { + ...mockNftTransferPartsFragment, + direction: TransactionDirection.In, + }, + ], + }, +} as AssetActivityPartsFragment + +export const MockNFTPurchase = { + ...mockAssetActivityPartsFragment, + details: { + ...commonTransactionDetailsFields, + type: TransactionType.Swap, + assetChanges: [ + mockTokenTransferOutPartsFragment, + { + ...mockNftTransferPartsFragment, + direction: TransactionDirection.In, + }, + ], + }, +} as AssetActivityPartsFragment diff --git a/src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.test.tsx b/src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.test.tsx new file mode 100644 index 0000000000..a6038c4f64 --- /dev/null +++ b/src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.test.tsx @@ -0,0 +1,126 @@ +import { act, renderHook } from '@testing-library/react' +import ms from 'ms' + +import { + MockClosedUniswapXOrder, + MockMoonpayPurchase, + MockNFTApproval, + MockNFTApprovalForAll, + MockNFTPurchase, + MockNFTReceive, + MockNFTTransfer, + MockOpenUniswapXOrder, + MockRemoveLiquidity, + MockSwapOrder, + MockTokenApproval, + MockTokenReceive, + MockTokenSend, + MockTokenTransfer, +} from './fixtures/activity' +import { parseRemoteActivities, useTimeSince } from './parseRemote' + +describe('parseRemote', () => { + beforeEach(() => { + jest.useFakeTimers() + }) + describe('parseRemoteActivities', () => { + it('should not parse open UniswapX order', () => { + const result = parseRemoteActivities(jest.fn(), [MockOpenUniswapXOrder]) + expect(result).toEqual({}) + }) + it('should parse closed UniswapX order', () => { + const result = parseRemoteActivities(jest.fn(), [MockClosedUniswapXOrder]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse NFT approval', () => { + const result = parseRemoteActivities(jest.fn(), [MockNFTApproval]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse NFT approval for all', () => { + const result = parseRemoteActivities(jest.fn(), [MockNFTApprovalForAll]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse NFT transfer', () => { + const result = parseRemoteActivities(jest.fn(), [MockNFTTransfer]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse swap', () => { + const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockTokenTransfer]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse nft purchase', () => { + const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockNFTPurchase]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse token approval', () => { + const result = parseRemoteActivities(jest.fn(), [MockTokenApproval]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse send', () => { + const result = parseRemoteActivities(jest.fn().mockReturnValue(100), [MockTokenSend]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse receive', () => { + const result = parseRemoteActivities(jest.fn().mockReturnValue(100), [MockTokenReceive]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse NFT receive', () => { + const result = parseRemoteActivities(jest.fn().mockReturnValue(100), [MockNFTReceive]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse remove liquidity', () => { + const result = parseRemoteActivities(jest.fn().mockReturnValue(100), [MockRemoveLiquidity]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse moonpay purchase', () => { + const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockMoonpayPurchase]) + expect(result?.['someHash']).toMatchSnapshot() + }) + it('should parse swap order', () => { + const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockSwapOrder]) + expect(result?.['someHash']).toMatchSnapshot() + }) + }) + + describe('useTimeSince', () => { + beforeEach(() => { + jest.useFakeTimers() + }) + + afterEach(() => { + jest.useRealTimers() + }) + + it('should initialize with the correct time since', () => { + const timestamp = Math.floor(Date.now() / 1000) - 60 // 60 seconds ago + const { result } = renderHook(() => useTimeSince(timestamp)) + + expect(result.current).toBe('1m') + }) + + it('should update time since every second', async () => { + const timestamp = Math.floor(Date.now() / 1000) - 50 // 50 seconds ago + const { result, rerender } = renderHook(() => useTimeSince(timestamp)) + + act(() => { + jest.advanceTimersByTime(ms('1.1s')) + }) + rerender() + + expect(result.current).toBe('51s') + }) + + it('should stop updating after 61 seconds', () => { + const timestamp = Math.floor(Date.now() / 1000) - 61 // 61 seconds ago + const { result, rerender } = renderHook(() => useTimeSince(timestamp)) + + act(() => { + jest.advanceTimersByTime(ms('121.1s')) + }) + rerender() + + // maxes out at 1m + expect(result.current).toBe('1m') + }) + }) +}) diff --git a/src/graphql/data/util.tsx b/src/graphql/data/util.tsx index 2e27b30dcf..65ce6f2d8b 100644 --- a/src/graphql/data/util.tsx +++ b/src/graphql/data/util.tsx @@ -118,7 +118,7 @@ export function gqlToCurrency(token: { const chainId = supportedChainIdFromGQLChain(token.chain) if (!chainId) return undefined if (token.standard === TokenStandard.Native || !token.address) return nativeOnChain(chainId) - else return new Token(chainId, token.address, token.decimals ?? 18, token.name, token.symbol) + else return new Token(chainId, token.address, token.decimals ?? 18, token.symbol, token.name) } const URL_CHAIN_PARAM_TO_BACKEND: { [key: string]: InterfaceGqlChain } = {