From 954713a0eff26a6397a4ba97696234999ee01cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Tue, 1 May 2018 13:46:36 +0100 Subject: [PATCH] Removed default support for @providesModule --- packages/jest-haste-map/package.json | 1 - .../__snapshots__/index.test.js.snap | 116 +++- .../src/__tests__/haste_impl.js | 8 +- .../src/__tests__/index.test.js | 548 +++++++----------- .../src/__tests__/worker.test.js | 77 +-- packages/jest-haste-map/src/worker.js | 4 - 6 files changed, 347 insertions(+), 407 deletions(-) diff --git a/packages/jest-haste-map/package.json b/packages/jest-haste-map/package.json index d6f5924c601a..69a89d48d5e3 100644 --- a/packages/jest-haste-map/package.json +++ b/packages/jest-haste-map/package.json @@ -10,7 +10,6 @@ "dependencies": { "fb-watchman": "^2.0.0", "graceful-fs": "^4.1.11", - "jest-docblock": "^22.4.0", "jest-serializer": "^22.4.0", "jest-worker": "^22.2.2", "micromatch": "^2.3.11", diff --git a/packages/jest-haste-map/src/__tests__/__snapshots__/index.test.js.snap b/packages/jest-haste-map/src/__tests__/__snapshots__/index.test.js.snap index 4e1c96ddd868..f44cd4cd1ae4 100644 --- a/packages/jest-haste-map/src/__tests__/__snapshots__/index.test.js.snap +++ b/packages/jest-haste-map/src/__tests__/__snapshots__/index.test.js.snap @@ -1,25 +1,119 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`HasteMap builds a haste map on a fresh cache with SHA-1s uses watchman: false 1`] = ` +Object { + "/fruits/Banana.js": Array [ + "Banana", + 32, + 1, + Array [ + "Strawberry", + ], + "5ed33593647e9ed632d8133a91b2dbef416a5d77", + ], + "/fruits/Pear.js": Array [ + "Pear", + 32, + 1, + Array [ + "Banana", + "Strawberry", + ], + "210aa3531d1646b6469d88d80168417f8dd08c7f", + ], + "/fruits/Strawberry.js": Array [ + "Strawberry", + 32, + 1, + Array [], + "65a371cc1a610b7cad68798d6d4ff5a941f837b8", + ], + "/fruits/__mocks__/Pear.js": Array [ + "", + 32, + 1, + Array [ + "Melon", + ], + "e0753bafe7b1f7a460fe8af9925f15e79960bb20", + ], + "/vegetables/Melon.js": Array [ + "Melon", + 32, + 1, + Array [], + "ff9c3f399d8f8bc7e67f99d065efff6570ce9347", + ], +} +`; + +exports[`HasteMap builds a haste map on a fresh cache with SHA-1s uses watchman: true 1`] = ` +Object { + "/fruits/Banana.js": Array [ + "Banana", + 32, + 1, + Array [ + "Strawberry", + ], + "5ed33593647e9ed632d8133a91b2dbef416a5d77", + ], + "/fruits/Pear.js": Array [ + "Pear", + 32, + 1, + Array [ + "Banana", + "Strawberry", + ], + "210aa3531d1646b6469d88d80168417f8dd08c7f", + ], + "/fruits/Strawberry.js": Array [ + "Strawberry", + 32, + 1, + Array [], + "65a371cc1a610b7cad68798d6d4ff5a941f837b8", + ], + "/fruits/__mocks__/Pear.js": Array [ + "", + 32, + 1, + Array [ + "Melon", + ], + "e0753bafe7b1f7a460fe8af9925f15e79960bb20", + ], + "/vegetables/Melon.js": Array [ + "Melon", + 32, + 1, + Array [], + "ff9c3f399d8f8bc7e67f99d065efff6570ce9347", + ], +} +`; + exports[`HasteMap file system changes processing recovery from duplicate module IDs recovers when the most recent duplicate is fixed 1`] = ` "The name \`Pear\` was looked up in the Haste module map. It cannot be resolved, because there exists several different files, or packages, that provide a module for that particular name and platform. The platform is generic (no extension). You must delete or blacklist files until there remains only one of these: - * \`/fruits/blueberry.js\` (module) - * \`/fruits/pear.js\` (module) + * \`/fruits/Pear.js\` (module) + * \`/fruits/another/Pear.js\` (module) " `; exports[`HasteMap file system changes processing recovery from duplicate module IDs recovers when the oldest version of the duplicates is fixed 1`] = ` "The name \`Pear\` was looked up in the Haste module map. It cannot be resolved, because there exists several different files, or packages, that provide a module for that particular name and platform. The platform is generic (no extension). You must delete or blacklist files until there remains only one of these: - * \`/fruits/blueberry.js\` (module) - * \`/fruits/pear.js\` (module) + * \`/fruits/Pear.js\` (module) + * \`/fruits/another/Pear.js\` (module) " `; exports[`HasteMap throws on duplicate module ids if "throwOnModuleCollision" is set to true 1`] = ` [Error: jest-haste-map: @providesModule naming collision: Duplicate module name: Strawberry - Paths: /fruits/raspberry.js collides with /fruits/strawberry.js + Paths: /fruits/another/Strawberry.js collides with /fruits/Strawberry.js This error is caused by a @providesModule declaration with the same name across two different files.] `; @@ -32,14 +126,14 @@ exports[`HasteMap tries to crawl using node as a fallback 1`] = ` exports[`HasteMap warns on duplicate mock files 1`] = ` "jest-haste-map: duplicate manual mock found: - Module name: subdir/blueberry - Duplicate Mock path: /fruits2/__mocks__/subdir/blueberry.js + Module name: blueberry + Duplicate Mock path: /fruits/dir2/__mocks__/blueberry.js This warning is caused by two manual mock files with the same file name. Jest will use the mock file found in: -/fruits2/__mocks__/subdir/blueberry.js +/fruits/dir2/__mocks__/blueberry.js Please delete one of the following two files: - /fruits1/__mocks__/subdir/blueberry.js -/fruits2/__mocks__/subdir/blueberry.js + /fruits/dir1/__mocks__/blueberry.js +/fruits/dir2/__mocks__/blueberry.js " `; @@ -47,7 +141,7 @@ Jest will use the mock file found in: exports[`HasteMap warns on duplicate module ids 1`] = ` "jest-haste-map: @providesModule naming collision: Duplicate module name: Strawberry - Paths: /fruits/raspberry.js collides with /fruits/strawberry.js + Paths: /fruits/another/Strawberry.js collides with /fruits/Strawberry.js This warning is caused by a @providesModule declaration with the same name across two different files." `; diff --git a/packages/jest-haste-map/src/__tests__/haste_impl.js b/packages/jest-haste-map/src/__tests__/haste_impl.js index 59a10b6912a2..1405d95025b8 100644 --- a/packages/jest-haste-map/src/__tests__/haste_impl.js +++ b/packages/jest-haste-map/src/__tests__/haste_impl.js @@ -8,6 +8,12 @@ module.exports = { getHasteName(path) { - return path.substr(path.lastIndexOf('/') + 1).replace(/\.js$/, ''); + if (path.includes('__mocks__') || path.includes('NoHaste')) { + return undefined; + } + + return path + .substr(path.lastIndexOf('/') + 1) + .replace(/(\.(android|ios))?\.js$/, ''); }, }; diff --git a/packages/jest-haste-map/src/__tests__/index.test.js b/packages/jest-haste-map/src/__tests__/index.test.js index 5920d0ae7905..5d4006e3a3ed 100644 --- a/packages/jest-haste-map/src/__tests__/index.test.js +++ b/packages/jest-haste-map/src/__tests__/index.test.js @@ -117,6 +117,7 @@ let object; let mockEnd; let mockWorker; let getCacheFilePath; +let hasteImplModulePath; describe('HasteMap', () => { SkipOnWindows.suite(); @@ -128,31 +129,19 @@ describe('HasteMap', () => { mockEmitters = Object.create(null); mockFs = object({ - '/fruits/__mocks__/Pear.js': ['const Melon = require("Melon");'].join( - '\n', - ), - '/fruits/banana.js': [ - '/**', - ' * @providesModule Banana', - ' */', - 'const Strawberry = require("Strawberry");', - ].join('\n'), - '/fruits/kiwi.js': ['/**', ' * @providesModule Kiwi', ' */'].join('\n'), - '/fruits/pear.js': [ - '/**', - ' * @providesModule Pear', - ' */', - 'const Banana = require("Banana");', - 'const Strawberry = require("Strawberry");', - ].join('\n'), - '/fruits/strawberry.js': [ - '/**', - ' * @providesModule Strawberry', - ' */', - ].join('\n'), - '/vegetables/melon.js': ['/**', ' * @providesModule Melon', ' */'].join( - '\n', - ), + '/fruits/Banana.js': ` + const Strawberry = require('Strawberry'); + `, + '/fruits/KiwiNoHaste.js': 'const foo = 1;', + '/fruits/Pear.js': ` + const Banana = require('Banana'); + const Strawberry = require('Strawberry'); + `, + '/fruits/Strawberry.js': 'const bar = 1;', + '/fruits/__mocks__/Pear.js': ` + const Melon = require('Melon'); + `, + '/vegetables/Melon.js': 'const baz = 2;', '/video/video.mp4': Buffer.from([0xfa, 0xce, 0xb0, 0x0c]).toString(), }); mockClocks = object({ @@ -174,9 +163,12 @@ describe('HasteMap', () => { getCacheFilePath = HasteMap.getCacheFilePath; HasteMap.getCacheFilePath = jest.fn(() => cacheFilePath); + hasteImplModulePath = require.resolve('./haste_impl.js'); + defaultConfig = { extensions: ['js', 'json'], - ignorePattern: /kiwi/, + hasteImplModulePath, + ignorePattern: /Kiwi/, maxWorkers: 1, name: 'haste-map-test', platforms: ['ios', 'android'], @@ -212,10 +204,10 @@ describe('HasteMap', () => { it('matches files against a pattern', () => { return new HasteMap(defaultConfig).build().then(({hasteFS}) => { expect(hasteFS.matchFiles(/fruits/)).toEqual([ + '/fruits/Banana.js', + '/fruits/Pear.js', + '/fruits/Strawberry.js', '/fruits/__mocks__/Pear.js', - '/fruits/banana.js', - '/fruits/pear.js', - '/fruits/strawberry.js', ]); expect(hasteFS.matchFiles(/__mocks__/)).toEqual([ @@ -226,45 +218,31 @@ describe('HasteMap', () => { it('builds a haste map on a fresh cache', () => { // Include these files in the map - mockFs['/fruits/node_modules/react/react.js'] = [ - '/**', - ' * @providesModule React', - ' */', - 'const Component = require("Component");', - ].join('\n'); - mockFs['/fruits/node_modules/fbjs/lib/flatMap.js'] = [ - '/**', - ' * @providesModule flatMap', - ' */', - ].join('\n'); + mockFs['/fruits/node_modules/react/React.js'] = ` + const Component = require('Component'); + `; + mockFs['/fruits/node_modules/fbjs/lib/flatMap.js'] = ` + function flatMap() {} + `; // Ignore these - mockFs['/fruits/node_modules/react/node_modules/fbjs/lib/mapObject.js'] = [ - '/**', - ' * @providesModule mapObject', - ' */', - ].join('\n'); - mockFs['/fruits/node_modules/react/node_modules/dummy/merge.js'] = [ - '/**', - ' * @providesModule merge', - ' */', - ].join('\n'); - mockFs['/fruits/node_modules/react/node_modules/merge/package.json'] = [ - '{', - ' "name": "merge"', - '}', - ].join('\n'); - mockFs['/fruits/node_modules/jest/jest.js'] = [ - '/**', - ' * @providesModule Jest', - ' */', - 'const Test = require("Test");', - ].join('\n'); - mockFs['/fruits/node_modules/fbjs2/index.js'] = [ - '/**', - ' * @providesModule fbjs2', - ' */', - ].join('\n'); + mockFs['/fruits/node_modules/react/node_modules/fbjs/lib/mapObject.js'] = ` + module.exports = function mapObject() {}; + `; + mockFs['/fruits/node_modules/react/node_modules/dummy/merge.js'] = ` + module.exports = function merge() {}; + `; + mockFs['/fruits/node_modules/react/node_modules/merge/package.json'] = ` + { + "name": "merge" + } + `; + mockFs['/fruits/node_modules/jest/jest.js'] = ` + const Test = require('Test'); + `; + mockFs['/fruits/node_modules/fbjs2/fbjs2.js'] = ` + const fbjs2 = 3; + `; const hasteMap = new HasteMap( Object.assign({}, defaultConfig, { @@ -277,8 +255,10 @@ describe('HasteMap', () => { expect(data.clocks).toEqual(mockClocks); expect(data.files).toEqual({ + '/fruits/Banana.js': ['Banana', 32, 1, ['Strawberry'], null], + '/fruits/Pear.js': ['Pear', 32, 1, ['Banana', 'Strawberry'], null], + '/fruits/Strawberry.js': ['Strawberry', 32, 1, [], null], '/fruits/__mocks__/Pear.js': ['', 32, 1, ['Melon'], null], - '/fruits/banana.js': ['Banana', 32, 1, ['Strawberry'], null], // node modules '/fruits/node_modules/fbjs/lib/flatMap.js': [ 'flatMap', @@ -287,31 +267,28 @@ describe('HasteMap', () => { [], null, ], - '/fruits/node_modules/react/react.js': [ + '/fruits/node_modules/react/React.js': [ 'React', 32, 1, ['Component'], null, ], - - '/fruits/pear.js': ['Pear', 32, 1, ['Banana', 'Strawberry'], null], - '/fruits/strawberry.js': ['Strawberry', 32, 1, [], null], - '/vegetables/melon.js': ['Melon', 32, 1, [], null], + '/vegetables/Melon.js': ['Melon', 32, 1, [], null], }); expect(data.map).toEqual({ - Banana: {[H.GENERIC_PLATFORM]: ['/fruits/banana.js', H.MODULE]}, - Melon: {[H.GENERIC_PLATFORM]: ['/vegetables/melon.js', H.MODULE]}, - Pear: {[H.GENERIC_PLATFORM]: ['/fruits/pear.js', H.MODULE]}, + Banana: {[H.GENERIC_PLATFORM]: ['/fruits/Banana.js', H.MODULE]}, + Melon: {[H.GENERIC_PLATFORM]: ['/vegetables/Melon.js', H.MODULE]}, + Pear: {[H.GENERIC_PLATFORM]: ['/fruits/Pear.js', H.MODULE]}, React: { [H.GENERIC_PLATFORM]: [ - '/fruits/node_modules/react/react.js', + '/fruits/node_modules/react/React.js', H.MODULE, ], }, Strawberry: { - [H.GENERIC_PLATFORM]: ['/fruits/strawberry.js', H.MODULE], + [H.GENERIC_PLATFORM]: ['/fruits/Strawberry.js', H.MODULE], }, flatMap: { [H.GENERIC_PLATFORM]: [ @@ -341,11 +318,11 @@ describe('HasteMap', () => { // The node crawler returns "null" for the SHA-1. data.files = object({ + '/fruits/Banana.js': ['Banana', 32, 0, ['Strawberry'], null], + '/fruits/Pear.js': ['Pear', 32, 0, ['Banana', 'Strawberry'], null], + '/fruits/Strawberry.js': ['Strawberry', 32, 0, [], null], '/fruits/__mocks__/Pear.js': ['', 32, 0, ['Melon'], null], - '/fruits/banana.js': ['Banana', 32, 0, ['Strawberry'], null], - '/fruits/pear.js': ['Pear', 32, 0, ['Banana', 'Strawberry'], null], - '/fruits/strawberry.js': ['Strawberry', 32, 0, [], null], - '/vegetables/melon.js': ['Melon', 32, 0, [], null], + '/vegetables/Melon.js': ['Melon', 32, 0, [], null], }); return Promise.resolve(data); @@ -361,43 +338,7 @@ describe('HasteMap', () => { const data = (await hasteMap.build()).__hasteMapForTest; - expect(data.files).toEqual({ - '/fruits/__mocks__/Pear.js': [ - '', - 32, - 1, - ['Melon'], - 'a315b7804be2b124b77c1f107205397f45226964', - ], - '/fruits/banana.js': [ - 'Banana', - 32, - 1, - ['Strawberry'], - 'f24c6984cce6f032f6d55d771d04ab8dbbe63c8c', - ], - '/fruits/pear.js': [ - 'Pear', - 32, - 1, - ['Banana', 'Strawberry'], - '211a8ff1e67007b204727d26943c15cf9fd00031', - ], - '/fruits/strawberry.js': [ - 'Strawberry', - 32, - 1, - [], - 'd55d545ad7d997cb2aa10fb412e0cc287d4fbfb3', - ], - '/vegetables/melon.js': [ - 'Melon', - 32, - 1, - [], - '45c5d30e29313187829dfd5a16db81c3143fbcc7', - ], - }); + expect(data.files).toMatchSnapshot(); expect(hasteMap.read()).toEqual(data); }); @@ -405,13 +346,9 @@ describe('HasteMap', () => { }); it('does not crawl native files even if requested to do so', async () => { - mockFs['/video/i-require-a-video.js'] = [ - '/**', - ' * @providesModule IRequireAVideo', - ' */', - 'module.exports = require("./video.mp4");', - ].join('\n'); - + mockFs['/video/IRequireAVideo.js'] = ` + module.exports = require('./'ideo.mp4"); + `; const hasteMap = new HasteMap( Object.assign({}, defaultConfig, { extensions: [...defaultConfig.extensions], @@ -427,11 +364,9 @@ describe('HasteMap', () => { }); it('retains all files if `retainAllFiles` is specified', () => { - mockFs['/fruits/node_modules/fbjs/index.js'] = [ - '/**', - ' * @providesModule fbjs', - ' */', - ].join('\n'); + mockFs['/fruits/node_modules/fbjs/fbjs.js'] = ` + module.exports = {}; + `; const hasteMap = new HasteMap( Object.assign({}, defaultConfig, { @@ -443,7 +378,7 @@ describe('HasteMap', () => { return hasteMap.build().then(({__hasteMapForTest: data}) => { // Expect the node module to be part of files but make sure it wasn't // read. - expect(data.files['/fruits/node_modules/fbjs/index.js']).toEqual([ + expect(data.files['/fruits/node_modules/fbjs/fbjs.js']).toEqual([ '', 32, 0, @@ -460,34 +395,23 @@ describe('HasteMap', () => { it('warns on duplicate mock files', () => { // Duplicate mock files for blueberry - mockFs['/fruits1/__mocks__/subdir/blueberry.js'] = [ - '/**', - ' * @providesModule Blueberry1', - ' */', - ].join('\n'); - mockFs['/fruits2/__mocks__/subdir/blueberry.js'] = [ - '/**', - ' * @providesModule Blueberry2', - ' */', - ].join('\n'); + mockFs['/fruits/dir1/__mocks__/blueberry.js'] = '// foo'; + mockFs['/fruits/dir2/__mocks__/blueberry.js'] = '// bar'; return new HasteMap( Object.assign({mocksPattern: '__mocks__'}, defaultConfig), ) .build() - .then(({__hasteMapForTest: data}) => { + .then(() => { expect(console.warn.mock.calls[0][0]).toMatchSnapshot(); }); }); it('warns on duplicate module ids', () => { - // Raspberry thinks it is a Strawberry - mockFs['/fruits/raspberry.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Banana = require("Banana");', - ].join('\n'); + // Strawberry in a different location + mockFs['/fruits/another/Strawberry.js'] = ` + const Banana = require('Banana'); + `; return new HasteMap(defaultConfig) .build() @@ -501,13 +425,10 @@ describe('HasteMap', () => { }); it('throws on duplicate module ids if "throwOnModuleCollision" is set to true', () => { - // Raspberry thinks it is a Strawberry - mockFs['/fruits/raspberry.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Banana = require("Banana");', - ].join('\n'); + // Strawberry in a different location + mockFs['/fruits/another/Strawberry.js'] = ` + const Banana = require('Banana'); + `; return new HasteMap( Object.assign({throwOnModuleCollision: true}, defaultConfig), @@ -520,53 +441,44 @@ describe('HasteMap', () => { it('splits up modules by platform', () => { mockFs = Object.create(null); - mockFs['/fruits/strawberry.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Banana = require("Banana");', - ].join('\n'); - - mockFs['/fruits/strawberry.ios.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Raspberry = require("Raspberry");', - ].join('\n'); - - mockFs['/fruits/strawberry.android.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Blackberry = require("Blackberry");', - ].join('\n'); + mockFs['/fruits/Strawberry.js'] = ` + const Banana = require('Banana'); + `; + + mockFs['/fruits/Strawberry.ios.js'] = ` + const Banana = require('Raspberry'); + `; + + mockFs['/fruits/Strawberry.android.js'] = ` + const Banana = require('Blackberry'); + `; return new HasteMap(defaultConfig) .build() .then(({__hasteMapForTest: data}) => { expect(data.files).toEqual({ - '/fruits/strawberry.android.js': [ + '/fruits/Strawberry.android.js': [ 'Strawberry', 32, 1, ['Blackberry'], null, ], - '/fruits/strawberry.ios.js': [ + '/fruits/Strawberry.ios.js': [ 'Strawberry', 32, 1, ['Raspberry'], null, ], - '/fruits/strawberry.js': ['Strawberry', 32, 1, ['Banana'], null], + '/fruits/Strawberry.js': ['Strawberry', 32, 1, ['Banana'], null], }); expect(data.map).toEqual({ Strawberry: { - [H.GENERIC_PLATFORM]: ['/fruits/strawberry.js', H.MODULE], - android: ['/fruits/strawberry.android.js', H.MODULE], - ios: ['/fruits/strawberry.ios.js', H.MODULE], + [H.GENERIC_PLATFORM]: ['/fruits/Strawberry.js', H.MODULE], + android: ['/fruits/Strawberry.android.js', H.MODULE], + ios: ['/fruits/Strawberry.ios.js', H.MODULE], }, }); }); @@ -615,12 +527,9 @@ describe('HasteMap', () => { // Let's assume one JS file has changed. mockChangedFiles = object({ - '/fruits/banana.js': [ - '/**', - ' * @providesModule Kiwi', // Identity crisis. - ' */', - 'const Raspberry = require("Raspberry");', - ].join('\n'), + '/fruits/Banana.js': ` + const Raspberry = require('Raspberry'); + `, }); // Watchman would give us different clocks for `/fruits`. @@ -639,20 +548,14 @@ describe('HasteMap', () => { } else { expect(fs.readFileSync).toBeCalledWith(cacheFilePath, 'utf8'); } - expect(fs.readFileSync).toBeCalledWith('/fruits/banana.js', 'utf8'); + expect(fs.readFileSync).toBeCalledWith('/fruits/Banana.js', 'utf8'); expect(data.clocks).toEqual(mockClocks); const files = object(initialData.files); - files['/fruits/banana.js'] = ['Kiwi', 32, 1, ['Raspberry'], null]; + files['/fruits/Banana.js'] = ['Banana', 32, 1, ['Raspberry'], null]; expect(data.files).toEqual(files); - - const map = object(initialData.map); - - map.Kiwi = map.Banana; - delete map.Banana; - expect(data.map).toEqual(map); }); }); }); @@ -664,9 +567,9 @@ describe('HasteMap', () => { fs.readFileSync.mockClear(); // Let's assume one JS file was removed. - delete mockFs['/fruits/banana.js']; + delete mockFs['/fruits/Banana.js']; mockChangedFiles = object({ - '/fruits/banana.js': null, + '/fruits/Banana.js': null, }); // Watchman would give us different clocks for `/fruits`. @@ -679,7 +582,7 @@ describe('HasteMap', () => { .build() .then(({__hasteMapForTest: data}) => { const files = object(initialData.files); - delete files['/fruits/banana.js']; + delete files['/fruits/Banana.js']; expect(data.files).toEqual(files); const map = object(initialData.map); @@ -691,120 +594,102 @@ describe('HasteMap', () => { it('correctly handles platform-specific file additions', async () => { mockFs = Object.create(null); - mockFs['/fruits/strawberry.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Banana = require("Banana");', - ].join('\n'); + mockFs['/fruits/Strawberry.js'] = ` + const Banana = require('Banana'); + `; let data; ({__hasteMapForTest: data} = await new HasteMap(defaultConfig).build()); expect(data.map['Strawberry']).toEqual({ - g: ['/fruits/strawberry.js', 0], + g: ['/fruits/Strawberry.js', 0], }); - delete mockFs['/fruits/strawberry.ios.js']; + delete mockFs['/fruits/Strawberry.ios.js']; mockChangedFiles = object({ - '/fruits/strawberry.ios.js': [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Raspberry = require("Raspberry");', - ].join('\n'), + '/fruits/Strawberry.ios.js': ` + const Raspberry = require('Raspberry'); + `, }); mockClocks = object({'/fruits': 'c:fake-clock:3'}); ({__hasteMapForTest: data} = await new HasteMap(defaultConfig).build()); expect(data.map['Strawberry']).toEqual({ - g: ['/fruits/strawberry.js', 0], - ios: ['/fruits/strawberry.ios.js', 0], + g: ['/fruits/Strawberry.js', 0], + ios: ['/fruits/Strawberry.ios.js', 0], }); }); it('correctly handles platform-specific file deletions', async () => { mockFs = Object.create(null); - mockFs['/fruits/strawberry.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Banana = require("Banana");', - ].join('\n'); - mockFs['/fruits/strawberry.ios.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Raspberry = require("Raspberry");', - ].join('\n'); + mockFs['/fruits/Strawberry.js'] = ` + const Banana = require('Banana'); + `; + mockFs['/fruits/Strawberry.ios.js'] = ` + const Raspberry = require('Raspberry'); + `; let data; ({__hasteMapForTest: data} = await new HasteMap(defaultConfig).build()); expect(data.map['Strawberry']).toEqual({ - g: ['/fruits/strawberry.js', 0], - ios: ['/fruits/strawberry.ios.js', 0], + g: ['/fruits/Strawberry.js', 0], + ios: ['/fruits/Strawberry.ios.js', 0], }); - delete mockFs['/fruits/strawberry.ios.js']; - mockChangedFiles = object({'/fruits/strawberry.ios.js': null}); + delete mockFs['/fruits/Strawberry.ios.js']; + mockChangedFiles = object({'/fruits/Strawberry.ios.js': null}); mockClocks = object({'/fruits': 'c:fake-clock:3'}); ({__hasteMapForTest: data} = await new HasteMap(defaultConfig).build()); expect(data.map['Strawberry']).toEqual({ - g: ['/fruits/strawberry.js', 0], + g: ['/fruits/Strawberry.js', 0], }); }); it('correctly handles platform-specific file renames', async () => { mockFs = Object.create(null); - mockFs['/fruits/strawberry.ios.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Raspberry = require("Raspberry");', - ].join('\n'); + mockFs['/fruits/Strawberry.ios.js'] = ` + const Raspberry = require('Raspberry'); + `; let data; ({__hasteMapForTest: data} = await new HasteMap(defaultConfig).build()); expect(data.map['Strawberry']).toEqual({ - ios: ['/fruits/strawberry.ios.js', 0], + ios: ['/fruits/Strawberry.ios.js', 0], }); - delete mockFs['/fruits/strawberry.ios.js']; + delete mockFs['/fruits/Strawberry.ios.js']; mockChangedFiles = object({ - '/fruits/strawberry.ios.js': null, - '/fruits/strawberry.js': [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Banana = require("Banana");', - ].join('\n'), + '/fruits/Strawberry.ios.js': null, + '/fruits/Strawberry.js': ` + const Banana = require('Banana'); + `, }); mockClocks = object({'/fruits': 'c:fake-clock:3'}); ({__hasteMapForTest: data} = await new HasteMap(defaultConfig).build()); expect(data.map['Strawberry']).toEqual({ - g: ['/fruits/strawberry.js', 0], + g: ['/fruits/Strawberry.js', 0], }); }); describe('duplicate modules', () => { beforeEach(async () => { - mockFs['/fruits/another_strawberry.js'] = [ - '/**', - ' * @providesModule Strawberry', - ' */', - 'const Blackberry = require("Blackberry");', - ].join('\n'); + mockFs['/fruits/another/Strawberry.js'] = ` + const Blackberry = require('Blackberry'); + `; const {__hasteMapForTest: data} = await new HasteMap( defaultConfig, ).build(); expect(data.duplicates).toEqual({ Strawberry: { - g: {'/fruits/another_strawberry.js': 0, '/fruits/strawberry.js': 0}, + g: { + '/fruits/Strawberry.js': 0, + '/fruits/another/Strawberry.js': 0, + }, }, }); expect(data.map['Strawberry']).toEqual({}); }); it('recovers when a duplicate file is deleted', async () => { - delete mockFs['/fruits/another_strawberry.js']; + delete mockFs['/fruits/another/Strawberry.js']; mockChangedFiles = object({ - '/fruits/another_strawberry.js': null, + '/fruits/another/Strawberry.js': null, }); mockClocks = object({ '/fruits': 'c:fake-clock:3', @@ -815,19 +700,17 @@ describe('HasteMap', () => { defaultConfig, ).build(); expect(data.duplicates).toEqual({}); - expect(data.map['Strawberry']).toEqual({g: ['/fruits/strawberry.js', 0]}); + expect(data.map['Strawberry']).toEqual({g: ['/fruits/Strawberry.js', 0]}); // Make sure the other files are not affected. - expect(data.map['Banana']).toEqual({g: ['/fruits/banana.js', 0]}); + expect(data.map['Banana']).toEqual({g: ['/fruits/Banana.js', 0]}); }); it('recovers when a duplicate module is renamed', async () => { mockChangedFiles = object({ - '/fruits/another_strawberry.js': [ - '/**', - ' * @providesModule AnotherStrawberry', - ' */', - 'const Blackberry = require("Blackberry");', - ].join('\n'), + '/fruits/another/AnotherStrawberry.js': ` + const Blackberry = require('Blackberry'); + `, + '/fruits/another/Strawberry.js': null, }); mockClocks = object({ '/fruits': 'c:fake-clock:3', @@ -838,12 +721,12 @@ describe('HasteMap', () => { defaultConfig, ).build(); expect(data.duplicates).toEqual({}); - expect(data.map['Strawberry']).toEqual({g: ['/fruits/strawberry.js', 0]}); + expect(data.map['Strawberry']).toEqual({g: ['/fruits/Strawberry.js', 0]}); expect(data.map['AnotherStrawberry']).toEqual({ - g: ['/fruits/another_strawberry.js', 0], + g: ['/fruits/another/AnotherStrawberry.js', 0], }); // Make sure the other files are not affected. - expect(data.map['Banana']).toEqual({g: ['/fruits/banana.js', 0]}); + expect(data.map['Banana']).toEqual({g: ['/fruits/Banana.js', 0]}); }); }); @@ -908,36 +791,36 @@ describe('HasteMap', () => { [ { computeSha1: false, - filePath: '/fruits/__mocks__/Pear.js', - hasteImplModulePath: undefined, + filePath: '/fruits/Banana.js', + hasteImplModulePath, }, ], [ { computeSha1: false, - filePath: '/fruits/banana.js', - hasteImplModulePath: undefined, + filePath: '/fruits/Pear.js', + hasteImplModulePath, }, ], [ { computeSha1: false, - filePath: '/fruits/pear.js', - hasteImplModulePath: undefined, + filePath: '/fruits/Strawberry.js', + hasteImplModulePath, }, ], [ { computeSha1: false, - filePath: '/fruits/strawberry.js', - hasteImplModulePath: undefined, + filePath: '/fruits/__mocks__/Pear.js', + hasteImplModulePath, }, ], [ { computeSha1: false, - filePath: '/vegetables/melon.js', - hasteImplModulePath: undefined, + filePath: '/vegetables/Melon.js', + hasteImplModulePath, }, ], ]); @@ -956,7 +839,7 @@ describe('HasteMap', () => { node.mockImplementation(options => { const {data} = options; data.files = object({ - '/fruits/banana.js': ['', 32, 0, [], null], + '/fruits/Banana.js': ['', 32, 0, [], null], }); return Promise.resolve(data); }); @@ -968,7 +851,7 @@ describe('HasteMap', () => { expect(node).toBeCalled(); expect(data.files).toEqual({ - '/fruits/banana.js': ['Banana', 32, 1, ['Strawberry'], null], + '/fruits/Banana.js': ['Banana', 32, 1, ['Strawberry'], null], }); expect(console.warn.mock.calls[0][0]).toMatchSnapshot(); @@ -985,7 +868,7 @@ describe('HasteMap', () => { node.mockImplementation(options => { const {data} = options; data.files = object({ - '/fruits/banana.js': ['', 32, 0, [], null], + '/fruits/Banana.js': ['', 32, 0, [], null], }); return Promise.resolve(data); }); @@ -997,7 +880,7 @@ describe('HasteMap', () => { expect(node).toBeCalled(); expect(data.files).toEqual({ - '/fruits/banana.js': ['Banana', 32, 1, ['Strawberry'], null], + '/fruits/Banana.js': ['Banana', 32, 1, ['Strawberry'], null], }); }); }); @@ -1057,11 +940,11 @@ describe('HasteMap', () => { hm_it('provides a new set of hasteHS and moduleMap', async hm => { const initialResult = await hm.build(); - const filePath = '/fruits/banana.js'; + const filePath = '/fruits/Banana.js'; expect(initialResult.hasteFS.getModuleName(filePath)).toBeDefined(); expect(initialResult.moduleMap.getModule('Banana')).toBe(filePath); - mockDeleteFile('/fruits', 'banana.js'); - mockDeleteFile('/fruits', 'banana.js'); + mockDeleteFile('/fruits', 'Banana.js'); + mockDeleteFile('/fruits', 'Banana.js'); const {eventsQueue, hasteFS, moduleMap} = await waitForItToChange(hm); expect(eventsQueue).toHaveLength(1); const deletedBanana = {filePath, stat: undefined, type: 'delete'}; @@ -1076,36 +959,31 @@ describe('HasteMap', () => { const MOCK_STAT = {mtime: {getTime: () => 45}}; hm_it('handles several change events at once', async hm => { - mockFs['/fruits/tomato.js'] = [ - '/**', - ' * @providesModule Tomato', - ' */', - ].join('\n'); - mockFs['/fruits/pear.js'] = [ - '/**', - ' * @providesModule Kiwi', - ' */', - ].join('\n'); + mockFs['/fruits/Tomato.js'] = ` + module.exports = {}; + `; + mockFs['/fruits/Pear.js'] = ` + module.exports = {}; + `; const e = mockEmitters['/fruits']; - e.emit('all', 'add', 'tomato.js', '/fruits', MOCK_STAT); - e.emit('all', 'change', 'pear.js', '/fruits', MOCK_STAT); + e.emit('all', 'add', 'Tomato.js', '/fruits', MOCK_STAT); + e.emit('all', 'change', 'Pear.js', '/fruits', MOCK_STAT); const {eventsQueue, hasteFS, moduleMap} = await waitForItToChange(hm); expect(eventsQueue).toEqual([ { - filePath: '/fruits/tomato.js', + filePath: '/fruits/Tomato.js', stat: MOCK_STAT, type: 'add', }, { - filePath: '/fruits/pear.js', + filePath: '/fruits/Pear.js', stat: MOCK_STAT, type: 'change', }, ]); - expect(hasteFS.getModuleName('/fruits/tomato.js')).not.toBeNull(); + expect(hasteFS.getModuleName('/fruits/Tomato.js')).not.toBeNull(); expect(moduleMap.getModule('Tomato')).toBeDefined(); - expect(moduleMap.getModule('Pear')).toBeNull(); - expect(moduleMap.getModule('Kiwi')).toBe('/fruits/pear.js'); + expect(moduleMap.getModule('Pear')).toBe('/fruits/Pear.js'); }); hm_it('does not emit duplicate change events', async hm => { @@ -1157,38 +1035,30 @@ describe('HasteMap', () => { }, { mockFs: { - '/fruits/Orange.android.js': [ - '/**', - ' * @providesModule Orange', - ' */', - ].join('\n'), - - '/fruits/Orange.ios.js': [ - '/**', - ' * @providesModule Orange', - ' */', - ].join('\n'), + '/fruits/Orange.android.js': ` + module.exports = {}; + `, + + '/fruits/Orange.ios.js': ` + module.exports = {}; + `, }, }, ); describe('recovery from duplicate module IDs', () => { async function setupDuplicates(hm) { - mockFs['/fruits/pear.js'] = [ - '/**', - ' * @providesModule Pear', - ' */', - ].join('\n'); - mockFs['/fruits/blueberry.js'] = [ - '/**', - ' * @providesModule Pear', - ' */', - ].join('\n'); + mockFs['/fruits/Pear.js'] = ` + module.exports = {}; + `; + mockFs['/fruits/another/Pear.js'] = ` + module.exports = {}; + `; const e = mockEmitters['/fruits']; - e.emit('all', 'change', 'pear.js', '/fruits', MOCK_STAT); - e.emit('all', 'add', 'blueberry.js', '/fruits', MOCK_STAT); + e.emit('all', 'change', 'Pear.js', '/fruits', MOCK_STAT); + e.emit('all', 'add', 'Pear.js', '/fruits/another', MOCK_STAT); const {hasteFS, moduleMap} = await waitForItToChange(hm); - expect(hasteFS.exists('/fruits/blueberry.js')).toBe(true); + expect(hasteFS.exists('/fruits/another/Pear.js')).toBe(true); try { moduleMap.getModule('Pear'); throw new Error('should be unreachable'); @@ -1201,8 +1071,8 @@ describe('HasteMap', () => { expect(error.platform).toBe('g'); expect(error.supportsNativePlatform).toBe(false); expect(error.duplicatesSet).toEqual({ - '/fruits/blueberry.js': 0, - '/fruits/pear.js': 0, + '/fruits/Pear.js': 0, + '/fruits/another/Pear.js': 0, }); expect(error.message).toMatchSnapshot(); } @@ -1212,32 +1082,20 @@ describe('HasteMap', () => { 'recovers when the oldest version of the duplicates is fixed', async hm => { await setupDuplicates(hm); - mockFs['/fruits/pear.js'] = [ - '/**', - ' * @providesModule OldPear', - ' */', - ].join('\n'); const e = mockEmitters['/fruits']; - e.emit('all', 'change', 'pear.js', '/fruits', MOCK_STAT); + e.emit('all', 'delete', 'Pear.js', '/fruits', MOCK_STAT); const {moduleMap} = await waitForItToChange(hm); - expect(moduleMap.getModule('Pear')).toBe('/fruits/blueberry.js'); - expect(moduleMap.getModule('OldPear')).toBe('/fruits/pear.js'); - expect(moduleMap.getModule('Blueberry')).toBe(null); + expect(moduleMap.getModule('Pear')).toBe('/fruits/another/Pear.js'); }, ); hm_it('recovers when the most recent duplicate is fixed', async hm => { await setupDuplicates(hm); - mockFs['/fruits/blueberry.js'] = [ - '/**', - ' * @providesModule Blueberry', - ' */', - ].join('\n'); + mockFs['/fruits/another/Strawberry.js'] = ''; const e = mockEmitters['/fruits']; - e.emit('all', 'change', 'blueberry.js', '/fruits', MOCK_STAT); + e.emit('all', 'delete', 'Pear.js', '/fruits/another', MOCK_STAT); const {moduleMap} = await waitForItToChange(hm); - expect(moduleMap.getModule('Pear')).toBe('/fruits/pear.js'); - expect(moduleMap.getModule('Blueberry')).toBe('/fruits/blueberry.js'); + expect(moduleMap.getModule('Pear')).toBe('/fruits/Pear.js'); }); }); }); diff --git a/packages/jest-haste-map/src/__tests__/worker.test.js b/packages/jest-haste-map/src/__tests__/worker.test.js index 3d7a26557c53..6b933345a2f4 100644 --- a/packages/jest-haste-map/src/__tests__/worker.test.js +++ b/packages/jest-haste-map/src/__tests__/worker.test.js @@ -9,43 +9,34 @@ 'use strict'; import path from 'path'; -import fs from 'graceful-fs'; import SkipOnWindows from '../../../../scripts/SkipOnWindows'; import H from '../constants'; -const {worker} = require('../worker'); - -let mockFs; -let readFileSync; +let worker; describe('worker', () => { SkipOnWindows.suite(); beforeEach(() => { - mockFs = { - '/fruits/banana.js': [ - '/**', - ' * @providesModule Banana', - ' */', - 'const Strawberry = require("Strawberry");', - ].join('\n'), - '/fruits/pear.js': [ - '/**', - ' * @providesModule Pear', - ' */', - 'const Banana = require("Banana");', - 'const Strawberry = require(`Strawberry`);', - ].join('\n'), - '/fruits/strawberry.js': [ - '/**', - ' * @providesModule Strawberry', - ' */', - ].join('\n'), + jest.resetModules(); + + worker = require('../worker').worker; + + const fs = require('graceful-fs'); + + const mockFs = { + '/fruits/Banana.js': ` + const Strawberry = require("Strawberry"); + `, + '/fruits/Pear.js': ` + const Banana = require("Banana"); + const Strawberry = require('Strawberry'); + `, + '/fruits/Strawberry.js': '// foo', '/package.json': ['{', ' "name": "haste-package"', '}'].join('\n'), }; - readFileSync = fs.readFileSync; fs.readFileSync = jest.fn((path, options) => { expect(options).toBe('utf8'); @@ -57,31 +48,13 @@ describe('worker', () => { }); }); - afterEach(() => { - fs.readFileSync = readFileSync; - }); - - it('parses JavaScript files and extracts module information', async () => { - expect(await worker({filePath: '/fruits/pear.js'})).toEqual({ - dependencies: ['Banana', 'Strawberry'], - id: 'Pear', - module: ['/fruits/pear.js', H.MODULE], - }); - - expect(await worker({filePath: '/fruits/strawberry.js'})).toEqual({ - dependencies: [], - id: 'Strawberry', - module: ['/fruits/strawberry.js', H.MODULE], - }); - }); - it('delegates to hasteImplModulePath for getting the id', async () => { const moduleData = await worker({ - filePath: '/fruits/strawberry.js', + filePath: '/fruits/Strawberry.js', hasteImplModulePath: path.resolve(__dirname, 'haste_impl.js'), }); - expect(moduleData.id).toBe('strawberry'); + expect(moduleData.id).toBe('Strawberry'); expect(moduleData).toEqual( expect.objectContaining({ dependencies: expect.any(Array), @@ -91,6 +64,20 @@ describe('worker', () => { ); }); + it('does not assign a module id if there is no hasteImpl', async () => { + const moduleData = await worker({ + filePath: '/fruits/Strawberry.js', + }); + + expect(moduleData).toEqual( + expect.objectContaining({ + dependencies: expect.any(Array), + id: undefined, + module: undefined, + }), + ); + }); + it('parses package.json files as haste packages', async () => { expect(await worker({filePath: '/package.json'})).toEqual({ dependencies: undefined, diff --git a/packages/jest-haste-map/src/worker.js b/packages/jest-haste-map/src/worker.js index 969e384dbbc2..6819b9010d02 100644 --- a/packages/jest-haste-map/src/worker.js +++ b/packages/jest-haste-map/src/worker.js @@ -11,7 +11,6 @@ import type {HasteImpl, WorkerMessage, WorkerMetadata} from './types'; import crypto from 'crypto'; import path from 'path'; -import * as docblock from 'jest-docblock'; import fs from 'graceful-fs'; import blacklist from './blacklist'; import H from './constants'; @@ -58,9 +57,6 @@ export async function worker(data: WorkerMessage): Promise { if (hasteImpl) { id = hasteImpl.getHasteName(filePath); - } else { - const doc = docblock.parse(docblock.extract(content)); - id = [].concat(doc.providesModule || doc.provides)[0]; } dependencies = extractRequires(content);