diff --git a/packages/metro-memory-fs/src/index.js b/packages/metro-memory-fs/src/index.js index 8fb2eb5d..104b47b2 100644 --- a/packages/metro-memory-fs/src/index.js +++ b/packages/metro-memory-fs/src/index.js @@ -88,6 +88,7 @@ const ASYNC_FUNC_NAMES = [ 'readdir', 'readFile', 'realpath', + 'stat', 'write', 'writeFile', ]; diff --git a/packages/metro/src/Assets/__tests__/Assets-test.js b/packages/metro/src/Assets/__tests__/Assets-test.js index a3b21118..759e82b4 100644 --- a/packages/metro/src/Assets/__tests__/Assets-test.js +++ b/packages/metro/src/Assets/__tests__/Assets-test.js @@ -10,12 +10,14 @@ 'use strict'; -jest.mock('fs'); +jest.mock('fs', () => new (require('metro-memory-fs'))()); jest.mock('image-size'); const {getAssetData, getAsset} = require('../'); const crypto = require('crypto'); const fs = require('fs'); +const mkdirp = require('mkdirp'); +const path = require('path'); const mockImageWidth = 300; const mockImageHeight = 200; @@ -26,41 +28,35 @@ require('image-size').mockReturnValue({ }); describe('getAsset', () => { + beforeEach(() => { + fs.reset(); + mkdirp.sync('/root/imgs'); + }); + it('should work for the simple case', () => { - fs.__setMockFilesystem({ - root: { - imgs: { - 'b.png': 'b image', - 'b@2x.png': 'b2 image', - }, - }, - }); + writeImages({'b.png': 'b image', 'b@2x.png': 'b2 image'}); return Promise.all([ - getAsset('imgs/b.png', ['/root']), - getAsset('imgs/b@1x.png', ['/root']), + getAssetStr('imgs/b.png', ['/root']), + getAssetStr('imgs/b@1x.png', ['/root']), ]).then(resp => resp.forEach(data => expect(data).toBe('b image'))); }); it('should work for the simple case with platform ext', async () => { - fs.__setMockFilesystem({ - root: { - imgs: { - 'b.ios.png': 'b ios image', - 'b.android.png': 'b android image', - 'c.png': 'c general image', - 'c.android.png': 'c android image', - }, - }, + writeImages({ + 'b.ios.png': 'b ios image', + 'b.android.png': 'b android image', + 'c.png': 'c general image', + 'c.android.png': 'c android image', }); expect( await Promise.all([ - getAsset('imgs/b.png', ['/root'], 'ios'), - getAsset('imgs/b.png', ['/root'], 'android'), - getAsset('imgs/c.png', ['/root'], 'android'), - getAsset('imgs/c.png', ['/root'], 'ios'), - getAsset('imgs/c.png', ['/root']), + getAssetStr('imgs/b.png', ['/root'], 'ios'), + getAssetStr('imgs/b.png', ['/root'], 'android'), + getAssetStr('imgs/c.png', ['/root'], 'android'), + getAssetStr('imgs/c.png', ['/root'], 'ios'), + getAssetStr('imgs/c.png', ['/root']), ]), ).toEqual([ 'b ios image', @@ -72,93 +68,71 @@ describe('getAsset', () => { }); it('should work for the simple case with jpg', () => { - fs.__setMockFilesystem({ - root: { - imgs: { - 'b.png': 'png image', - 'b.jpg': 'jpeg image', - }, - }, + writeImages({ + 'b.png': 'png image', + 'b.jpg': 'jpeg image', }); return Promise.all([ - getAsset('imgs/b.jpg', ['/root']), - getAsset('imgs/b.png', ['/root']), + getAssetStr('imgs/b.jpg', ['/root']), + getAssetStr('imgs/b.png', ['/root']), ]).then(data => expect(data).toEqual(['jpeg image', 'png image'])); }); it('should pick the bigger one', async () => { - fs.__setMockFilesystem({ - root: { - imgs: { - 'b@1x.png': 'b1 image', - 'b@2x.png': 'b2 image', - 'b@4x.png': 'b4 image', - 'b@4.5x.png': 'b4.5 image', - }, - }, + writeImages({ + 'b@1x.png': 'b1 image', + 'b@2x.png': 'b2 image', + 'b@4x.png': 'b4 image', + 'b@4.5x.png': 'b4.5 image', }); - expect(await getAsset('imgs/b@3x.png', ['/root'])).toBe('b4 image'); + expect(await getAssetStr('imgs/b@3x.png', ['/root'])).toBe('b4 image'); }); it('should pick the bigger one with platform ext', async () => { - fs.__setMockFilesystem({ - root: { - imgs: { - 'b@1x.png': 'b1 image', - 'b@2x.png': 'b2 image', - 'b@4x.png': 'b4 image', - 'b@4.5x.png': 'b4.5 image', - 'b@1x.ios.png': 'b1 ios image', - 'b@2x.ios.png': 'b2 ios image', - 'b@4x.ios.png': 'b4 ios image', - 'b@4.5x.ios.png': 'b4.5 ios image', - }, - }, + writeImages({ + 'b@1x.png': 'b1 image', + 'b@2x.png': 'b2 image', + 'b@4x.png': 'b4 image', + 'b@4.5x.png': 'b4.5 image', + 'b@1x.ios.png': 'b1 ios image', + 'b@2x.ios.png': 'b2 ios image', + 'b@4x.ios.png': 'b4 ios image', + 'b@4.5x.ios.png': 'b4.5 ios image', }); expect( await Promise.all([ - getAsset('imgs/b@3x.png', ['/root']), - getAsset('imgs/b@3x.png', ['/root'], 'ios'), + getAssetStr('imgs/b@3x.png', ['/root']), + getAssetStr('imgs/b@3x.png', ['/root'], 'ios'), ]), ).toEqual(['b4 image', 'b4 ios image']); }); it('should support multiple project roots', async () => { - fs.__setMockFilesystem({ - root: { - imgs: { - 'b.png': 'b image', - }, - }, - root2: { - newImages: { - imgs: { - 'b@1x.png': 'b1 image', - }, - }, - }, - }); + writeImages({'b.png': 'b image'}); + mkdirp.sync('/root2/newImages/imgs'); + fs.writeFileSync('/root2/newImages/imgs/b@1x.png', 'b1 image'); - expect(await getAsset('newImages/imgs/b.png', ['/root', '/root2'])).toBe( + expect(await getAssetStr('newImages/imgs/b.png', ['/root', '/root2'])).toBe( 'b1 image', ); }); }); describe('getAssetData', () => { + beforeEach(() => { + fs.reset(); + mkdirp.sync('/root/imgs'); + }); + it('should get assetData', () => { - fs.__setMockFilesystem({ - root: { - imgs: { - 'b@1x.png': 'b1 image', - 'b@2x.png': 'b2 image', - 'b@4x.png': 'b4 image', - 'b@4.5x.png': 'b4.5 image', - }, - }, + writeImages({ + 'b@1x.png': 'b1 image', + 'b@2x.png': 'b2 image', + 'b@4x.png': 'b4 image', + 'b@4.5x.png': 'b4.5 image', }); return getAssetData('/root/imgs/b.png', 'imgs/b.png', []).then(data => { @@ -182,15 +156,11 @@ describe('getAssetData', () => { }); it('should get assetData for non-png images', async () => { - fs.__setMockFilesystem({ - root: { - imgs: { - 'b@1x.jpg': 'b1 image', - 'b@2x.jpg': 'b2 image', - 'b@4x.jpg': 'b4 image', - 'b@4.5x.jpg': 'b4.5 image', - }, - }, + writeImages({ + 'b@1x.jpg': 'b1 image', + 'b@2x.jpg': 'b2 image', + 'b@4x.jpg': 'b4 image', + 'b@4.5x.jpg': 'b4.5 image', }); const data = await getAssetData('/root/imgs/b.jpg', 'imgs/b.jpg', []); @@ -240,14 +210,10 @@ describe('getAssetData', () => { {virtual: true}, ); - fs.__setMockFilesystem({ - root: { - imgs: { - 'b@1x.png': 'b1 image', - 'b@2x.png': 'b2 image', - 'b@3x.png': 'b3 image', - }, - }, + writeImages({ + 'b@1x.png': 'b1 image', + 'b@2x.png': 'b2 image', + 'b@3x.png': 'b3 image', }); const data = await getAssetData('/root/imgs/b.png', 'imgs/b.png', [ @@ -275,28 +241,20 @@ describe('getAssetData', () => { }); describe('hash:', () => { - let mockFS; - beforeEach(() => { - mockFS = { - root: { - imgs: { - 'b@1x.jpg': 'b1 image', - 'b@2x.jpg': 'b2 image', - 'b@4x.jpg': 'b4 image', - 'b@4.5x.jpg': 'b4.5 image', - }, - }, - }; - - fs.__setMockFilesystem(mockFS); + writeImages({ + 'b@1x.jpg': 'b1 image', + 'b@2x.jpg': 'b2 image', + 'b@4x.jpg': 'b4 image', + 'b@4.5x.jpg': 'b4.5 image', + }); }); it('uses the file contents to build the hash', async () => { const hash = crypto.createHash('md5'); - for (const name in mockFS.root.imgs) { - hash.update(mockFS.root.imgs[name]); + for (const name of fs.readdirSync('/root/imgs')) { + hash.update(fs.readFileSync(path.join('/root/imgs', name), 'utf8')); } expect(await getAssetData('/root/imgs/b.jpg', 'imgs/b.jpg', [])).toEqual( @@ -311,10 +269,21 @@ describe('getAssetData', () => { [], ); - mockFS.root.imgs['b@4x.jpg'] = 'updated data'; + fs.writeFileSync('/root/imgs/b@4x.jpg', 'updated data'); const data = await getAssetData('/root/imgs/b.jpg', 'imgs/b.jpg', []); expect(data.hash).not.toEqual(initialData.hash); }); }); }); + +function writeImages(imgMap) { + for (const fileName in imgMap) { + fs.writeFileSync(path.join('/root/imgs', fileName), imgMap[fileName]); + } +} + +async function getAssetStr(...args) { + const buffer = await getAsset(...args); + return buffer.toString('utf8'); +}