From c3e43cd1b4d36870f049dde747a8d9b350beea0c Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Thu, 22 Jun 2017 15:57:00 +0100 Subject: [PATCH] jest-haste-map: add test+fix for broken platform module support --- .../src/__tests__/index.test.js | 48 ++++++++++++++++++- packages/jest-haste-map/src/index.js | 18 ++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/packages/jest-haste-map/src/__tests__/index.test.js b/packages/jest-haste-map/src/__tests__/index.test.js index 1ad15236f1b5..b4356fcea25f 100644 --- a/packages/jest-haste-map/src/__tests__/index.test.js +++ b/packages/jest-haste-map/src/__tests__/index.test.js @@ -676,8 +676,12 @@ describe('HasteMap', () => { e.emit('all', 'delete', filePath, dirPath, undefined); } - function hm_it(title, fn) { - it(title, async () => { + function hm_it(title, fn, options) { + options = options || {}; + (options.only ? it.only : it)(title, async () => { + if (options.mockFs) { + mockFs = options.mockFs; + } const watchConfig = Object.assign({}, defaultConfig, {watch: true}); const hm = new HasteMap(watchConfig); await hm.build(); @@ -763,6 +767,46 @@ describe('HasteMap', () => { }, ); + hm_it( + 'correctly tracks changes to both platform-specific versions of a single module name', + async hm => { + const {moduleMap: initMM} = await hm.build(); + expect(initMM.getModule('Orange', 'ios')).toBeTruthy(); + expect(initMM.getModule('Orange', 'android')).toBeTruthy(); + const e = mockEmitters['/fruits']; + e.emit('all', 'change', 'Orange.ios.js', '/fruits/', MOCK_STAT); + e.emit('all', 'change', 'Orange.android.js', '/fruits/', MOCK_STAT); + const {eventsQueue, hasteFS, moduleMap} = await waitForItToChange(hm); + expect(eventsQueue).toHaveLength(2); + expect(eventsQueue).toEqual([ + {filePath: '/fruits/Orange.ios.js', stat: MOCK_STAT, type: 'change'}, + { + filePath: '/fruits/Orange.android.js', + stat: MOCK_STAT, + type: 'change', + }, + ]); + expect(hasteFS.getModuleName('/fruits/Orange.ios.js')).toBeTruthy(); + expect(hasteFS.getModuleName('/fruits/Orange.android.js')).toBeTruthy(); + const iosVariant = moduleMap.getModule('Orange', 'ios'); + expect(iosVariant).toBe('/fruits/Orange.ios.js'); + const androidVariant = moduleMap.getModule('Orange', 'android'); + expect(androidVariant).toBe('/fruits/Orange.android.js'); + }, + { + mockFs: { + '/fruits/Orange.android.js': `/** + * @providesModule Orange + */ +`, + '/fruits/Orange.ios.js': `/** +* @providesModule Orange +*/ +`, + }, + }, + ); + describe('recovery from duplicate module IDs', () => { async function setupDuplicates(hm) { mockFs['/fruits/pear.js'] = [ diff --git a/packages/jest-haste-map/src/index.js b/packages/jest-haste-map/src/index.js index b52a28e4c318..50aa9321d165 100644 --- a/packages/jest-haste-map/src/index.js +++ b/packages/jest-haste-map/src/index.js @@ -313,6 +313,7 @@ class HasteMap extends EventEmitter { const platform = getPlatformExtension(module[H.PATH], this._options.platforms) || H.GENERIC_PLATFORM; + const existingModule = moduleMap[platform]; if (existingModule && existingModule[H.PATH] !== module[H.PATH]) { const message = @@ -656,8 +657,23 @@ class HasteMap extends EventEmitter { // Delete the file and all of its metadata. const moduleName = hasteMap.files[filePath] && hasteMap.files[filePath][H.ID]; + const platform: string = + getPlatformExtension(filePath, this._options.platforms) || + H.GENERIC_PLATFORM; + delete hasteMap.files[filePath]; - delete hasteMap.map[moduleName]; + let moduleMap = hasteMap.map[moduleName]; + if (moduleMap != null) { + // We are forced to copy the object because jest-haste-map exposes + // the map as an immutable entity. + moduleMap = copy(moduleMap); + delete moduleMap[platform]; + if (Object.keys(moduleMap).length === 0) { + delete hasteMap.map[moduleName]; + } else { + hasteMap.map[moduleName] = moduleMap; + } + } if ( this._options.mocksPattern && this._options.mocksPattern.test(filePath)