diff --git a/app/components/UI/CollectibleMedia/CollectibleMedia.test.tsx b/app/components/UI/CollectibleMedia/CollectibleMedia.test.tsx index 9ee9cd1a2ef..76415fccb58 100644 --- a/app/components/UI/CollectibleMedia/CollectibleMedia.test.tsx +++ b/app/components/UI/CollectibleMedia/CollectibleMedia.test.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { waitFor } from '@testing-library/react-native'; import { CHAIN_IDS } from '@metamask/transaction-controller'; import CollectibleMedia from './CollectibleMedia'; @@ -6,6 +7,8 @@ import CollectibleMedia from './CollectibleMedia'; import renderWithProvider from '../../../util/test/renderWithProvider'; import { backgroundState } from '../../../util/test/initial-root-state'; import { mockNetworkState } from '../../../util/test/network'; +// eslint-disable-next-line import/no-namespace +import * as AssetControllers from '@metamask/assets-controllers'; const mockInitialState = { engine: { @@ -83,4 +86,47 @@ describe('CollectibleMedia', () => { const fallbackCollectible = getByTestId('nft-image'); expect(fallbackCollectible).toBeDefined(); }); + + it('should handle an nft with multiple images and render the first image', async () => { + const images = [ + 'ipfs://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy', + 'ipfs://bafybeic26kitpujb3q5h5w7yovmvgmtxl3y4ldsb2pfgual5jq62emsmxq', + ]; + + const mockGetFormattedIpfsUrl = jest + .spyOn(AssetControllers, 'getFormattedIpfsUrl') + .mockResolvedValue( + 'https://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy.ipfs.dweb.link', + ); + + const expectedUri = + 'https://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy.ipfs.dweb.link'; + + const { getByTestId } = renderWithProvider( + , + { state: mockInitialState }, + ); + + await new Promise((r) => setTimeout(r, 2000)); + + await waitFor(() => { + const elem = getByTestId('nft-image'); + expect(elem.props.source).toEqual({ uri: expectedUri }); + const mocksImageParam = mockGetFormattedIpfsUrl.mock.lastCall?.[1]; + expect(mocksImageParam).toBe(images[0]); + }); + }); }); diff --git a/app/components/UI/CollectibleMedia/CollectibleMedia.tsx b/app/components/UI/CollectibleMedia/CollectibleMedia.tsx index e73a5519537..996713bd3ba 100644 --- a/app/components/UI/CollectibleMedia/CollectibleMedia.tsx +++ b/app/components/UI/CollectibleMedia/CollectibleMedia.tsx @@ -22,6 +22,7 @@ import { strings } from '../../../../locales/i18n'; import { useNavigation } from '@react-navigation/native'; import Routes from '../../../constants/navigation/Routes'; import { useStyles } from '../../../component-library/hooks'; +import { getNftImage } from '../../../util/get-nft-image'; const CollectibleMedia: React.FC = ({ collectible, @@ -52,7 +53,7 @@ const CollectibleMedia: React.FC = ({ if (address) { if (small && imagePreview && imagePreview !== '') setSourceUri(imagePreview); - else setSourceUri((image || imageOriginal) ?? null); + else setSourceUri((getNftImage(image) || imageOriginal) ?? null); } }, [collectible, small, big, setSourceUri]); diff --git a/app/components/UI/CollectibleMedia/CollectibleMedia.types.ts b/app/components/UI/CollectibleMedia/CollectibleMedia.types.ts index 760cc9584cf..4837f0b135d 100644 --- a/app/components/UI/CollectibleMedia/CollectibleMedia.types.ts +++ b/app/components/UI/CollectibleMedia/CollectibleMedia.types.ts @@ -4,7 +4,7 @@ import { ViewStyle } from 'react-native'; export interface Collectible { name: string; tokenId: string; - image: string; + image: string | string[]; imagePreview: string; address: string; animation?: string; @@ -19,8 +19,12 @@ export interface Collectible { isCurrentlyOwned?: boolean; } +type NFTData = Omit & { + image: Nft['image'] | string[]; +}; + export interface CollectibleMediaProps { - collectible: Nft; + collectible: NFTData; tiny?: boolean; small?: boolean; big?: boolean; diff --git a/app/util/get-nft-image.test.ts b/app/util/get-nft-image.test.ts new file mode 100644 index 00000000000..bf9cba0fd16 --- /dev/null +++ b/app/util/get-nft-image.test.ts @@ -0,0 +1,31 @@ +import { getNftImage } from './get-nft-image'; + +describe('getNftImage', () => { + it('returns original image if string', () => { + const image = + 'ipfs://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy'; + const result = getNftImage(image); + expect(result).toBe(image); + }); + + it('returns the first image if image is an array', () => { + const image = [ + 'ipfs://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy', + 'ipfs://bafybeic26kitpujb3q5h5w7yovmvgmtxl3y4ldsb2pfgual5jq62emsmxq', + ]; + const result = getNftImage(image); + expect(result).toBe(image[0]); + }); + + it('returns undefined if image is missing', () => { + const image = undefined; + const result = getNftImage(image); + expect(result).toBeUndefined(); + }); + + it('returns undefined if image is not a type we were expecting ', () => { + const image = { badType: 'badType' } as unknown as string; + const result = getNftImage(image); + expect(result).toBeUndefined(); + }); +}); diff --git a/app/util/get-nft-image.ts b/app/util/get-nft-image.ts new file mode 100644 index 00000000000..b88e0aab39f --- /dev/null +++ b/app/util/get-nft-image.ts @@ -0,0 +1,12 @@ +type NFTImage = string | string[] | undefined | null; +export const getNftImage = (image: NFTImage): string | undefined => { + if (typeof image === 'string') { + return image; + } + + if (Array.isArray(image)) { + return image[0]; + } + + return undefined; +};