diff --git a/packages/jest-config/src/__tests__/normalize-test.js b/packages/jest-config/src/__tests__/normalize-test.js index f629caa8ac60..5a43faa86294 100644 --- a/packages/jest-config/src/__tests__/normalize-test.js +++ b/packages/jest-config/src/__tests__/normalize-test.js @@ -15,6 +15,7 @@ const utils = require('jest-util'); const normalize = require('../normalize'); const DEFAULT_JS_PATTERN = require('../constants').DEFAULT_JS_PATTERN; +const DEFAULT_TS_PATTERN = require('../constants').DEFAULT_TS_PATTERN; const DEFAULT_CSS_PATTERN = '^.+\\.(css)$'; describe('normalize', () => { @@ -614,6 +615,131 @@ describe('normalize', () => { }); }); + describe('ts-jest', () => { + let Resolver; + beforeEach(() => { + Resolver = require('jest-resolve'); + Resolver.findNodeModule = jest.fn( + name => 'node_modules' + path.sep + name, + ); + }); + + it('correctly identifies and uses ts-jest', () => { + const config = normalize({ + rootDir: '/root', + }); + const tsTransformerPath = uniformPath(config.transform[1][1]); + const testResultsProcessorPath = uniformPath(config.testResultsProcessor); + expect(config.transform[1][0]).toBe(DEFAULT_TS_PATTERN); + expect(tsTransformerPath) + .toEqual('/root/node_modules/ts-jest/preprocessor.js'); + expect(testResultsProcessorPath) + .toEqual('/root/node_modules/ts-jest/coverageprocessor.js'); + expect(config.moduleFileExtensions) + .toEqual(['js', 'jsx', 'json', 'ts', 'tsx']); + expect(config.testRegex) + .toEqual('(/__tests__/.*|\\.(test|spec))\\.(j|t)sx?$'); + }); + + it('uses ts-jest if ts-jest is explicitly specified in a custom transform config', () => { + const customTSPattern = '^.+\\.ts$'; + const ROOT_DIR = '' + path.sep; + const config = normalize({ + rootDir: '/root', + transform: { + [customTSPattern]: (ROOT_DIR + Resolver.findNodeModule( + 'ts-jest', + ) + path.sep + 'preprocessor.js'), + }, + }); + const tsTransformerPath = uniformPath(config.transform[0][1]); + const testResultsProcessorPath = uniformPath(config.testResultsProcessor); + expect(config.transform[0][0]).toBe(customTSPattern); + expect(tsTransformerPath) + .toEqual('/root/node_modules/ts-jest/preprocessor.js'); + expect(testResultsProcessorPath) + .toEqual('/root/node_modules/ts-jest/coverageprocessor.js'); + expect(config.moduleFileExtensions) + .toEqual(['js', 'jsx', 'json', 'ts', 'tsx']); + expect(config.testRegex) + .toEqual('(/__tests__/.*|\\.(test|spec))\\.(j|t)sx?$'); + }); + + it(`doesn't use ts-jest if its not available`, () => { + Resolver.findNodeModule.mockImplementation(() => null); + + const config = normalize({ + rootDir: '/root', + }); + + expect(config.transform).toEqual(undefined); + expect(config.testResultsProcessor).toEqual(undefined); + expect(config.moduleFileExtensions) + .toEqual(['js', 'json', 'jsx', 'node']); + expect(config.testRegex) + .toEqual('(/__tests__/.*|\\.(test|spec))\\.jsx?$'); + }); + + it(`doesn't use ts-jest coverage proccessor if another is defined`, () => { + const ROOT_DIR = '' + path.sep; + const config = normalize({ + rootDir: '/root', + testResultsProcessor: ROOT_DIR + 'anotherProcessor.js', + }); + const tsTransformerPath = uniformPath(config.transform[1][1]); + const testResultsProcessorPath = uniformPath(config.testResultsProcessor); + expect(config.transform[1][0]).toBe(DEFAULT_TS_PATTERN); + expect(tsTransformerPath) + .toEqual('/root/node_modules/ts-jest/preprocessor.js'); + expect(testResultsProcessorPath).not + .toEqual('/root/node_modules/ts-jest/coverageprocessor.js'); + expect(config.moduleFileExtensions) + .toEqual(['js', 'jsx', 'json', 'ts', 'tsx']); + expect(config.testRegex) + .toEqual('(/__tests__/.*|\\.(test|spec))\\.(j|t)sx?$'); + }); + + it(`doesn't use ts module extensions nor defalut if another is defined`, () => { + const config = normalize({ + moduleFileExtensions: ['js', 'ts'], + rootDir: '/root', + }); + const tsTransformerPath = uniformPath(config.transform[1][1]); + const testResultsProcessorPath = uniformPath(config.testResultsProcessor); + expect(config.transform[1][0]).toBe(DEFAULT_TS_PATTERN); + expect(tsTransformerPath) + .toEqual('/root/node_modules/ts-jest/preprocessor.js'); + expect(testResultsProcessorPath) + .toEqual('/root/node_modules/ts-jest/coverageprocessor.js'); + expect(config.moduleFileExtensions).not + .toEqual(['js', 'json', 'jsx', 'node']); + expect(config.moduleFileExtensions).not + .toEqual(['js', 'jsx', 'json', 'ts', 'tsx']); + expect(config.testRegex) + .toEqual('(/__tests__/.*|\\.(test|spec))\\.(j|t)sx?$'); + }); + + it(`doesn't use ts test Regex nor defalut if another is defined`, () => { + const config = normalize({ + rootDir: '/root', + testRegex: '\\.spec\\.tsx?$', + }); + const tsTransformerPath = uniformPath(config.transform[1][1]); + const testResultsProcessorPath = uniformPath(config.testResultsProcessor); + expect(config.transform[1][0]).toBe(DEFAULT_TS_PATTERN); + expect(tsTransformerPath) + .toEqual('/root/node_modules/ts-jest/preprocessor.js'); + expect(testResultsProcessorPath) + .toEqual('/root/node_modules/ts-jest/coverageprocessor.js'); + expect(config.moduleFileExtensions) + .toEqual(['js', 'jsx', 'json', 'ts', 'tsx']); + expect(config.testRegex).not + .toEqual('(/__tests__/.*|\\.(test|spec))\\.(j|t)sx?$'); + expect(config.testRegex).not + .toEqual('(/__tests__/.*|\\.(test|spec))\\.jsx?$'); + }); + }); + describe('Upgrade help', () => { let consoleWarn; diff --git a/packages/jest-config/src/constants.js b/packages/jest-config/src/constants.js index ff4cfa3efd2d..380b00b2a735 100644 --- a/packages/jest-config/src/constants.js +++ b/packages/jest-config/src/constants.js @@ -12,3 +12,4 @@ const path = require('path'); exports.NODE_MODULES = path.sep + 'node_modules' + path.sep; exports.DEFAULT_JS_PATTERN = '^.+\\.jsx?$'; +exports.DEFAULT_TS_PATTERN = '^.+\\.tsx?$'; diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index cd6556a4110b..78fe801ec62a 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -244,6 +244,7 @@ function normalize(config, argv) { } let babelJest; + let tsJest; if (config.transform) { const customJSPattern = Object.keys(config.transform).find(regex => { const pattern = new RegExp(regex); @@ -260,14 +261,40 @@ function normalize(config, argv) { babelJest = jsTransformer; } } + + const customTSPattern = Object.keys(config.transform).find(regex => { + const pattern = new RegExp(regex); + return pattern.test('foobar.ts') || pattern.test('foobar.tsx'); + }); + + if (customTSPattern) { + const tsTransformer = config.transform[customTSPattern]; + if ( + tsTransformer.includes( + constants.NODE_MODULES + 'ts-jest' + ) + ) { + tsJest = Resolver.findNodeModule('ts-jest', { + basedir: config.rootDir, + }); + } + } } else { babelJest = Resolver.findNodeModule('babel-jest', { basedir: config.rootDir, }); + tsJest = Resolver.findNodeModule('ts-jest', { + basedir: config.rootDir, + }); if (babelJest) { - config.transform = { + config.transform = Object.assign({}, config.transform, { [constants.DEFAULT_JS_PATTERN]: babelJest, - }; + }); + } + if (tsJest) { + config.transform = Object.assign({}, config.transform, { + [constants.DEFAULT_TS_PATTERN]: tsJest + '/preprocessor.js', + }); } } @@ -282,6 +309,18 @@ function normalize(config, argv) { config.usesBabelJest = true; } + if (tsJest) { + if (!config.testResultsProcessor) { + config.testResultsProcessor = tsJest + '/coverageprocessor.js'; + } + if (!config.moduleFileExtensions) { + config.moduleFileExtensions = ['js', 'jsx', 'json', 'ts', 'tsx']; + } + if (!config.testRegex) { + config.testRegex = '(/__tests__/.*|\\.(test|spec))\\.(j|t)sx?$'; + } + } + Object.keys(config).reduce((newConfig, key) => { let value; switch (key) {