jest.mock('expo-file-system', () => { const FileSystem = require.requireActual('expo-file-system'); return { ...FileSystem, bundleDirectory: 'file:///Expo.app/', cacheDirectory: 'file:///Caches/Expo.app/', bundledAssets: ['asset_test1.png'], getInfoAsync: jest.fn(), downloadAsync: jest.fn(), }; }); jest.mock('react-native/Libraries/Image/AssetRegistry', () => { return { getAssetByID: jest.fn(), }; }); jest.mock('react-native/Libraries/Image/resolveAssetSource', () => { return { default: jest.fn(), setCustomSourceTransformer: jest.fn(), }; }); jest.mock('../ImageAssets', () => { const ImageAssets = require.requireActual('../ImageAssets'); return { ...ImageAssets, getImageInfoAsync: jest.fn(), }; }); const mockImageMetadata = { name: 'test', type: 'png', hash: 'cafecafecafecafecafecafecafecafe', scales: [1], httpServerLocation: '/assets', }; afterEach(() => { jest.resetModules(); }); describe(`source resolution with React Native`, () => { it(`automatically registers a source resolver`, () => { require('../index'); const { setCustomSourceTransformer, } = require('react-native/Libraries/Image/resolveAssetSource'); expect(setCustomSourceTransformer).toHaveBeenCalledTimes(1); }); }); it(`creates assets from metadata`, () => { const { Asset } = require('../index'); let asset = Asset.fromMetadata(mockImageMetadata); expect(asset.hash).toBe('cafecafecafecafecafecafecafecafe'); }); it(`interns assets by hash`, () => { const { Asset } = require('../index'); let asset1 = Asset.fromMetadata(mockImageMetadata); let asset2 = Asset.fromMetadata(mockImageMetadata); expect(asset1).toBe(asset2); }); it(`creates assets from URIs`, () => { const { Asset } = require('../index'); let asset = Asset.fromURI('https://example.com/image.png'); expect(asset.uri).toBe('https://example.com/image.png'); expect(asset.type).toBe('png'); expect(asset.hash).toBeNull(); }); it(`creates assets from data URIs`, () => { const { Asset } = require('../index'); let asset = Asset.fromURI('data:text/html;base64,dGVzdA%3D%3D'); expect(asset.type).toBe('html'); }); it.skip(`supports non-Base64 data URIs`, () => { const { Asset } = require('../index'); let asset = Asset.fromURI('data:,test'); expect(asset.type).toBe('txt'); }); it(`interns assets by URI`, () => { const { Asset } = require('../index'); let uri = 'data:,Hello%2C%20World!'; let asset1 = Asset.fromURI(uri); let asset2 = Asset.fromURI(uri); expect(asset1).toBe(asset2); }); it(`creates assets from virtual modules`, () => { const { Asset } = require('../index'); const { getAssetByID } = require('react-native/Libraries/Image/AssetRegistry'); getAssetByID.mockReturnValueOnce(mockImageMetadata); let asset = Asset.fromModule(1); expect(asset.hash).toBe('cafecafecafecafecafecafecafecafe'); }); it(`throws when creating an asset from a missing module`, () => { const { Asset } = require('../index'); const { getAssetByID } = require('react-native/Libraries/Image/AssetRegistry'); getAssetByID.mockReturnValueOnce(undefined); expect(() => Asset.fromModule(2)).toThrowError(); }); it(`downloads uncached assets`, async () => { const FileSystem = require('expo-file-system'); const { Asset } = require('../index'); let asset = Asset.fromMetadata(mockImageMetadata); expect(asset.localUri).toBeNull(); FileSystem.getInfoAsync.mockReturnValueOnce({ exists: false }); FileSystem.downloadAsync.mockReturnValueOnce({ md5: mockImageMetadata.hash }); await asset.downloadAsync(); expect(asset.downloading).toBe(false); expect(asset.downloaded).toBe(true); expect(asset.localUri).toBe( 'file:///Caches/Expo.app/ExponentAsset-cafecafecafecafecafecafecafecafe.png' ); }); it(`throws when the file's checksum does not match`, async () => { const FileSystem = require('expo-file-system'); const { Asset } = require('../index'); let asset = Asset.fromMetadata(mockImageMetadata); expect(asset.localUri).toBeNull(); FileSystem.getInfoAsync.mockReturnValueOnce({ exists: false }); FileSystem.downloadAsync.mockReturnValueOnce({ md5: 'deadf00ddeadf00ddeadf00ddeadf00d' }); await expect(asset.downloadAsync()).rejects.toThrowError('failed MD5 integrity check'); }); it(`uses the local filesystem's cache directory for downloads`, async () => { const FileSystem = require('expo-file-system'); const { Asset } = require('../index'); let asset = Asset.fromMetadata(mockImageMetadata); FileSystem.getInfoAsync.mockReturnValueOnce({ exists: true, md5: mockImageMetadata.hash, }); await asset.downloadAsync(); expect(asset.downloaded).toBe(true); expect(FileSystem.downloadAsync).not.toHaveBeenCalled(); }); it(`coalesces downloads`, async () => { const FileSystem = require('expo-file-system'); const { Asset } = require('../index'); let asset = Asset.fromMetadata(mockImageMetadata); FileSystem.getInfoAsync.mockReturnValue({ exists: false }); FileSystem.downloadAsync.mockReturnValue({ md5: mockImageMetadata.hash }); await Promise.all([asset.downloadAsync(), asset.downloadAsync()]); expect(FileSystem.getInfoAsync).toHaveBeenCalledTimes(1); expect(FileSystem.downloadAsync).toHaveBeenCalledTimes(1); }); const { Platform } = require('@unimodules/core'); if (Platform.OS === 'web') { describe('web', () => { it(`fetches images to determine the dimensions`, async () => { const ImageAssets = require('../ImageAssets'); const { Asset } = require('../index'); let asset = Asset.fromMetadata(mockImageMetadata); ImageAssets.getImageInfoAsync.mockResolvedValueOnce({ width: 120, height: 180, name: 'test', }); await asset.downloadAsync(); expect(asset.width).toBe(120); expect(asset.height).toBe(180); expect(asset.downloaded).toBe(true); expect(asset.localUri).toBe(asset.uri); }); }); } describe('embedding', () => { beforeAll(() => { jest.doMock('expo-constants', () => { const Constants = require.requireActual('expo-constants'); return { ...Constants, appOwnership: 'standalone', manifest: {}, }; }); // @ts-ignore: the type declaration marks __DEV__ as read-only __DEV__ = false; }); afterAll(() => { jest.dontMock('expo-constants'); // @ts-ignore: the type declaration marks __DEV__ as read-only __DEV__ = true; }); it(`considers embedded assets to be downloaded`, () => { const { Asset } = require('../index'); let asset = Asset.fromMetadata({ ...mockImageMetadata, hash: 'test1', type: 'png', }); expect(asset.localUri).toBe('file:///Expo.app/asset_test1.png'); }); });