From 31ad0aa9e470661a4881d9350ef92ca17c533580 Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Mon, 24 Sep 2018 19:43:39 +0200 Subject: [PATCH 1/9] fix(cli): resets testMatch if using testRegex option Closes #756 --- src/cli/cli.spec.ts | 24 ++++++++++++++++++++++++ src/cli/config/migrate.ts | 6 +++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/cli/cli.spec.ts b/src/cli/cli.spec.ts index a30adb7412..da4164ff01 100644 --- a/src/cli/cli.spec.ts +++ b/src/cli/cli.spec.ts @@ -405,6 +405,29 @@ Migrated Jest configuration: `) }) + it('should reset testMatch if testRegex is used', async () => { + expect.assertions(1) + fs.existsSync.mockImplementation(() => true) + jest.mock( + pkgPaths.next, + () => ({ + jest: { + testRegex: 'foo-pattern', + }, + }), + { virtual: true }, + ) + const res = await runCli(...noOption, pkgPaths.current) + expect(res.stdout).toMatchInlineSnapshot(` +"{ + \\"testRegex\\": \\"foo-pattern\\", + \\"preset\\": \\"ts-jest\\", + \\"testMatch\\": null +} +" +`) + }) + it('should normalize transform values', async () => { expect.assertions(1) fs.existsSync.mockImplementation(() => true) @@ -434,6 +457,7 @@ Migrated Jest configuration: " `) }) + it('should output help', async () => { const res = await runCli('help', noOption[0]) expect(res).toMatchInlineSnapshot(` diff --git a/src/cli/config/migrate.ts b/src/cli/config/migrate.ts index f03e6d4b85..fe82846f73 100644 --- a/src/cli/config/migrate.ts +++ b/src/cli/config/migrate.ts @@ -50,8 +50,12 @@ export const run: CliCommand = async (args: Arguments /*, logger: Logger*/) => { delete migratedConfig.moduleFileExtensions } } + // there is a testRegex, remove our testMatch + if (migratedConfig.testRegex && usesPreset) { + migratedConfig.testMatch = null as any + } // check the testMatch - if (migratedConfig.testMatch && migratedConfig.testMatch.length && usesPreset) { + else if (migratedConfig.testMatch && migratedConfig.testMatch.length && usesPreset) { const presetValue = dedupSort(presets.testMatch).join('::') const migratedValue = dedupSort(migratedConfig.testMatch).join('::') if (presetValue === migratedValue) { From 3c325e8bacdc4508d48a9e1612412c8ad0f6fbc7 Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Mon, 24 Sep 2018 22:21:08 +0200 Subject: [PATCH 2/9] fix(preset): createJestPreset fails with base and no array If no moduleFileExtensions or testMatch is given to the createJestPreset it'd fail --- src/config/create-jest-preset.spec.ts | 43 +++++++++++++++++++++++++++ src/config/create-jest-preset.ts | 10 +++---- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/config/create-jest-preset.spec.ts b/src/config/create-jest-preset.spec.ts index 82bc1f3a5f..75e06a6aea 100644 --- a/src/config/create-jest-preset.spec.ts +++ b/src/config/create-jest-preset.spec.ts @@ -31,3 +31,46 @@ it('should return correct defaults when allowJs is true', () => { }, }) }) + +it('should be able to use a base config', () => { + expect(createJestPreset(undefined, {})).toMatchInlineSnapshot(` +Object { + "moduleFileExtensions": Array [ + "js", + "json", + "jsx", + "node", + "ts", + "tsx", + ], + "testMatch": Array [ + "**/__tests__/**/*.js?(x)", + "**/?(*.)+(spec|test).js?(x)", + "**/__tests__/**/*.ts?(x)", + "**/?(*.)+(spec|test).ts?(x)", + ], + "transform": Object { + "^.+\\\\.tsx?$": "ts-jest", + }, +} +`) + expect(createJestPreset(undefined, { testMatch: ['foo'], moduleFileExtensions: ['bar'], transform: { foo: 'bar' } })) + .toMatchInlineSnapshot(` +Object { + "moduleFileExtensions": Array [ + "bar", + "ts", + "tsx", + ], + "testMatch": Array [ + "foo", + "**/__tests__/**/*.ts?(x)", + "**/?(*.)+(spec|test).ts?(x)", + ], + "transform": Object { + "^.+\\\\.tsx?$": "ts-jest", + "foo": "bar", + }, +} +`) +}) diff --git a/src/config/create-jest-preset.ts b/src/config/create-jest-preset.ts index 07a2976ab0..01334190c7 100644 --- a/src/config/create-jest-preset.ts +++ b/src/config/create-jest-preset.ts @@ -12,18 +12,16 @@ const defaults = jestConfig.defaults || { moduleFileExtensions: ['js', 'json', 'jsx', 'node'], } -export function createJestPreset( - { allowJs = false }: CreateJestPresetOptions = {}, - from: jest.InitialOptions = defaults, -) { +export function createJestPreset({ allowJs = false }: CreateJestPresetOptions = {}, from?: jest.InitialOptions) { logger.debug({ allowJs }, 'creating jest presets', allowJs ? 'handling' : 'not handling', 'JavaScript files') + from = { ...defaults, ...from } return { transform: { ...from.transform, [allowJs ? '^.+\\.[tj]sx?$' : '^.+\\.tsx?$']: 'ts-jest', }, - testMatch: dedup([...from.testMatch, '**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)']), - moduleFileExtensions: dedup([...from.moduleFileExtensions, 'ts', 'tsx']), + testMatch: dedup([...(from.testMatch || []), '**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)']), + moduleFileExtensions: dedup([...(from.moduleFileExtensions || []), 'ts', 'tsx']), } } From 9f3d759be122560fd9751951a9f424364df66dd5 Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Mon, 24 Sep 2018 23:13:11 +0200 Subject: [PATCH 3/9] feat(preset): adds 2 presets along the default one Default preset `ts-jest` becomes an alias to `ts-jest/presets/default` which contains the same as previous `ts-jest` preset. Compilation of js files can be done using the `ts-jest/presets/js-with-ts` or `ts-jest/presets/js-with-babel` additional presets. --- jest-preset.js | 5 +---- presets/create.js | 1 + presets/default/jest-preset.js | 3 +++ presets/js-with-babel/jest-preset.js | 7 +++++++ presets/js-with-ts/jest-preset.js | 3 +++ 5 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 presets/create.js create mode 100644 presets/default/jest-preset.js create mode 100644 presets/js-with-babel/jest-preset.js create mode 100644 presets/js-with-ts/jest-preset.js diff --git a/jest-preset.js b/jest-preset.js index a2bdb3e099..54b108e345 100644 --- a/jest-preset.js +++ b/jest-preset.js @@ -1,4 +1 @@ -const createJestPreset = require('./dist/config/create-jest-preset') - .createJestPreset - -module.exports = createJestPreset() +module.exports = require('./presets/default/jest-preset') diff --git a/presets/create.js b/presets/create.js new file mode 100644 index 0000000000..50c361c351 --- /dev/null +++ b/presets/create.js @@ -0,0 +1 @@ +module.exports = require('../dist/config/create-jest-preset').createJestPreset diff --git a/presets/default/jest-preset.js b/presets/default/jest-preset.js new file mode 100644 index 0000000000..83a038128f --- /dev/null +++ b/presets/default/jest-preset.js @@ -0,0 +1,3 @@ +const create = require('../create') + +module.exports = create() diff --git a/presets/js-with-babel/jest-preset.js b/presets/js-with-babel/jest-preset.js new file mode 100644 index 0000000000..3248730a45 --- /dev/null +++ b/presets/js-with-babel/jest-preset.js @@ -0,0 +1,7 @@ +const create = require('../create') + +module.exports = create({ allowJs: false }, { + transform: { + '^.+\\.jsx?$': 'babel-jest', + }, +}) diff --git a/presets/js-with-ts/jest-preset.js b/presets/js-with-ts/jest-preset.js new file mode 100644 index 0000000000..639e6567be --- /dev/null +++ b/presets/js-with-ts/jest-preset.js @@ -0,0 +1,3 @@ +const create = require('../create') + +module.exports = create({allowJs: true}) From ad8f6d104a79d450289df0ce41ec63589a869d15 Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Mon, 24 Sep 2018 23:13:58 +0200 Subject: [PATCH 4/9] test(preset): e2e test for added presets --- e2e/__cases__/allow-js/esm.spec.js | 5 ++ e2e/__cases__/preset-with-babel/.babelrc | 5 ++ e2e/__cases__/preset-with-babel/main.spec.js | 3 + e2e/__helpers__/templates.ts | 6 ++ .../__snapshots__/allow-js.test.ts.snap | 78 +++++++++++++++++-- e2e/__tests__/allow-js.test.ts | 26 ++++++- e2e/__tests__/jest-presets.test.ts | 18 +++++ 7 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 e2e/__cases__/allow-js/esm.spec.js create mode 100644 e2e/__cases__/preset-with-babel/.babelrc create mode 100644 e2e/__cases__/preset-with-babel/main.spec.js create mode 100644 e2e/__tests__/jest-presets.test.ts diff --git a/e2e/__cases__/allow-js/esm.spec.js b/e2e/__cases__/allow-js/esm.spec.js new file mode 100644 index 0000000000..4672def549 --- /dev/null +++ b/e2e/__cases__/allow-js/esm.spec.js @@ -0,0 +1,5 @@ +import * as bar from './bar' + +test('esm', () => { + expect(bar).toBe('BAR!') +}) diff --git a/e2e/__cases__/preset-with-babel/.babelrc b/e2e/__cases__/preset-with-babel/.babelrc new file mode 100644 index 0000000000..a29ac9986c --- /dev/null +++ b/e2e/__cases__/preset-with-babel/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "@babel/preset-env" + ] +} diff --git a/e2e/__cases__/preset-with-babel/main.spec.js b/e2e/__cases__/preset-with-babel/main.spec.js new file mode 100644 index 0000000000..b804480001 --- /dev/null +++ b/e2e/__cases__/preset-with-babel/main.spec.js @@ -0,0 +1,3 @@ +test('spread', () => { + expect({ ...{ bar: 'foo' }, foo: 'bar' }).toEqual({ foo: 'bar', bar: 'foo' }) +}) diff --git a/e2e/__helpers__/templates.ts b/e2e/__helpers__/templates.ts index e367b63ef6..d1caae73f6 100644 --- a/e2e/__helpers__/templates.ts +++ b/e2e/__helpers__/templates.ts @@ -14,3 +14,9 @@ export const allValidPackageSets = [ PackageSets.jest22, PackageSets.typescript2_7, ] +export const allPackageSetsWithPreset = [ + PackageSets.default, + PackageSets.babel6, + PackageSets.babel7, + PackageSets.typescript2_7, +] diff --git a/e2e/__tests__/__snapshots__/allow-js.test.ts.snap b/e2e/__tests__/__snapshots__/allow-js.test.ts.snap index 33e8f288c0..d5369d6861 100644 --- a/e2e/__tests__/__snapshots__/allow-js.test.ts.snap +++ b/e2e/__tests__/__snapshots__/allow-js.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Allow JS test should pass using template "default" 1`] = ` +exports[`using babel-jest for js files should pass using template "default" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -17,7 +17,7 @@ exports[`Allow JS test should pass using template "default" 1`] = ` ================================================================================ `; -exports[`Allow JS test should pass using template "with-babel-6" 1`] = ` +exports[`using babel-jest for js files should pass using template "with-babel-6" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -34,7 +34,7 @@ exports[`Allow JS test should pass using template "with-babel-6" 1`] = ` ================================================================================ `; -exports[`Allow JS test should pass using template "with-babel-7" 1`] = ` +exports[`using babel-jest for js files should pass using template "with-babel-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -51,7 +51,7 @@ exports[`Allow JS test should pass using template "with-babel-7" 1`] = ` ================================================================================ `; -exports[`Allow JS test should pass using template "with-jest-22" 1`] = ` +exports[`using babel-jest for js files should pass using template "with-jest-22" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -68,7 +68,7 @@ exports[`Allow JS test should pass using template "with-jest-22" 1`] = ` ================================================================================ `; -exports[`Allow JS test should pass using template "with-typescript-2-7" 1`] = ` +exports[`using babel-jest for js files should pass using template "with-typescript-2-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -84,3 +84,71 @@ exports[`Allow JS test should pass using template "with-typescript-2-7" 1`] = ` Ran all test suites. ================================================================================ `; + +exports[`using ts-jest for js files should pass using template "default" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./esm.spec.js + √ esm + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`using ts-jest for js files should pass using template "with-babel-6" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./esm.spec.js + √ esm + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`using ts-jest for js files should pass using template "with-babel-7" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./esm.spec.js + √ esm + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`using ts-jest for js files should pass using template "with-typescript-2-7" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./esm.spec.js + √ esm + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; diff --git a/e2e/__tests__/allow-js.test.ts b/e2e/__tests__/allow-js.test.ts index b3a121b1a8..069aa58552 100644 --- a/e2e/__tests__/allow-js.test.ts +++ b/e2e/__tests__/allow-js.test.ts @@ -1,8 +1,10 @@ -import { allValidPackageSets } from '../__helpers__/templates' +import { allPackageSetsWithPreset, allValidPackageSets } from '../__helpers__/templates' import { configureTestCase } from '../__helpers__/test-case' -describe('Allow JS test', () => { - const testCase = configureTestCase('allow-js') +describe('using babel-jest for js files', () => { + const testCase = configureTestCase('allow-js', { + jestConfig: { testMatch: null, testRegex: '(foo|bar)\\.spec\\.[jt]s$' }, + }) testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { it(testLabel, () => { @@ -12,3 +14,21 @@ describe('Allow JS test', () => { }) }) }) + +describe('using ts-jest for js files', () => { + const testCase = configureTestCase('allow-js', { + jestConfig: { + preset: 'ts-jest/presets/js-with-ts', + testMatch: null, + testRegex: 'esm\\.spec\\.[jt]s$', + }, + }) + + testCase.runWithTemplates(allPackageSetsWithPreset, 0, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(0) + expect(result).toMatchSnapshot() + }) + }) +}) diff --git a/e2e/__tests__/jest-presets.test.ts b/e2e/__tests__/jest-presets.test.ts new file mode 100644 index 0000000000..730c6f0cf7 --- /dev/null +++ b/e2e/__tests__/jest-presets.test.ts @@ -0,0 +1,18 @@ +import { allPackageSetsWithPreset } from '../__helpers__/templates' +import { configureTestCase } from '../__helpers__/test-case' + +// 'ts-jest' is tested in almost all test cases +// 'ts-jest/presets/default' is an alias of the above +// 'ts-jest/presets/js-with-ts' is tested in allow-js.test.ts + +describe('ts-jest/presets/js-with-babel', () => { + const testCase = configureTestCase('preset-with-babel', { jestConfig: { preset: 'ts-jest/presets/js-with-babel' } }) + + testCase.runWithTemplates(allPackageSetsWithPreset, 1, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(1) + expect(result.stderr).toMatch(/(Couldn't|Cannot) find (preset|module) ["']@babel\/preset-env["']/) + }) + }) +}) From f55d8953300283df4d713960c08330fb583ebf9b Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Tue, 25 Sep 2018 07:48:10 +0200 Subject: [PATCH 5/9] feat(preset): adds presets typings and export all presets All presets are now accessible with typings by importing `ts-jest/presets` --- presets/default/jest-preset.js | 4 +--- presets/index.d.ts | 5 +++++ presets/index.js | 13 +++++++++++++ presets/js-with-babel/jest-preset.js | 8 +------- presets/js-with-ts/jest-preset.js | 4 +--- src/config/create-jest-preset.ts | 7 +++++-- src/types.ts | 6 ++++++ 7 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 presets/index.d.ts create mode 100644 presets/index.js diff --git a/presets/default/jest-preset.js b/presets/default/jest-preset.js index 83a038128f..bdbaf701a1 100644 --- a/presets/default/jest-preset.js +++ b/presets/default/jest-preset.js @@ -1,3 +1 @@ -const create = require('../create') - -module.exports = create() +module.exports = require('..').defaults diff --git a/presets/index.d.ts b/presets/index.d.ts new file mode 100644 index 0000000000..2d63d8e167 --- /dev/null +++ b/presets/index.d.ts @@ -0,0 +1,5 @@ +import { TsJestPresets } from '../dist/types' + +export const defaults: TsJesPresets +export const jsWithTs: TsJesPresets +export const jsWithBabel: TsJesPresets diff --git a/presets/index.js b/presets/index.js new file mode 100644 index 0000000000..73195684d3 --- /dev/null +++ b/presets/index.js @@ -0,0 +1,13 @@ +const create = './create' + +module.exports = { + get defaults() { return create() }, + get jsWithTs() { return create({ allowJs: true }) }, + get jsWithBabel() { + return create({ allowJs: false }, { + transform: { + '^.+\\.jsx?$': 'babel-jest', + }, + }) + }, +} diff --git a/presets/js-with-babel/jest-preset.js b/presets/js-with-babel/jest-preset.js index 3248730a45..7e252420ad 100644 --- a/presets/js-with-babel/jest-preset.js +++ b/presets/js-with-babel/jest-preset.js @@ -1,7 +1 @@ -const create = require('../create') - -module.exports = create({ allowJs: false }, { - transform: { - '^.+\\.jsx?$': 'babel-jest', - }, -}) +module.exports = require('..').jsWithBabel diff --git a/presets/js-with-ts/jest-preset.js b/presets/js-with-ts/jest-preset.js index 639e6567be..d549de07eb 100644 --- a/presets/js-with-ts/jest-preset.js +++ b/presets/js-with-ts/jest-preset.js @@ -1,3 +1 @@ -const create = require('../create') - -module.exports = create({allowJs: true}) +module.exports = require('..').jsWithTs diff --git a/src/config/create-jest-preset.ts b/src/config/create-jest-preset.ts index 01334190c7..999c500c20 100644 --- a/src/config/create-jest-preset.ts +++ b/src/config/create-jest-preset.ts @@ -1,6 +1,6 @@ import * as jestConfig from 'jest-config' -import { CreateJestPresetOptions } from '../types' +import { CreateJestPresetOptions, TsJestPresets } from '../types' import { rootLogger } from '../util/logger' const logger = rootLogger.child({ namespace: 'jest-preset' }) @@ -12,7 +12,10 @@ const defaults = jestConfig.defaults || { moduleFileExtensions: ['js', 'json', 'jsx', 'node'], } -export function createJestPreset({ allowJs = false }: CreateJestPresetOptions = {}, from?: jest.InitialOptions) { +export function createJestPreset( + { allowJs = false }: CreateJestPresetOptions = {}, + from?: jest.InitialOptions, +): TsJestPresets { logger.debug({ allowJs }, 'creating jest presets', allowJs ? 'handling' : 'not handling', 'JavaScript files') from = { ...defaults, ...from } return { diff --git a/src/types.ts b/src/types.ts index 7e9b84081a..6feff23c1c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -69,6 +69,12 @@ export interface TsJestGlobalOptions { stringifyContentPathRegex?: string | RegExp } +export interface TsJestPresets { + transform: Record + testMatch: string[] + moduleFileExtensions: string[] +} + interface TsJestConfig$tsConfig$file { kind: 'file' value: string | undefined From febd8d3be1ee31bbbd227fb94b9412657387b64f Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Tue, 25 Sep 2018 07:50:13 +0200 Subject: [PATCH 6/9] feat(cli): CLI 'config:migrate' now detects best preset When invoquing the CLI command `config:migrate`, it'll now be able to detect the best preset to be used. --- presets/index.js | 2 +- src/cli/config/migrate.ts | 72 ++++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/presets/index.js b/presets/index.js index 73195684d3..95cca6d7be 100644 --- a/presets/index.js +++ b/presets/index.js @@ -1,4 +1,4 @@ -const create = './create' +const create = require('./create') module.exports = { get defaults() { return create() }, diff --git a/src/cli/config/migrate.ts b/src/cli/config/migrate.ts index fe82846f73..a4cae6b848 100644 --- a/src/cli/config/migrate.ts +++ b/src/cli/config/migrate.ts @@ -6,9 +6,11 @@ import { basename, resolve } from 'path' import { Arguments } from 'yargs' import { CliCommand } from '..' -import { createJestPreset } from '../../config/create-jest-preset' +import { TsJestPresets } from '../../types' import { backportJestConfig } from '../../util/backports' +const DEFAULT_PRESET = 'ts-jest/presets/default' + /** * @internal */ @@ -16,6 +18,7 @@ export const run: CliCommand = async (args: Arguments /*, logger: Logger*/) => { const nullLogger = createLogger({ targets: [] }) const file = args._[0] const filePath = resolve(process.cwd(), file) + const footNotes: string[] = [] if (!existsSync(filePath)) { throw new Error(`Configuration file ${file} does not exists.`) } @@ -33,17 +36,59 @@ export const run: CliCommand = async (args: Arguments /*, logger: Logger*/) => { // migrate // first we backport our options const migratedConfig = backportJestConfig(nullLogger, actualConfig) + let presetName: string | undefined // then we check if we can use `preset` if (!migratedConfig.preset && args.jestPreset) { - migratedConfig.preset = 'ts-jest' - } else if (!args.jestPreset && migratedConfig.preset === 'ts-jest') { - delete migratedConfig.preset + // find the best preset + if (args.allowJs) presetName = 'ts-jest/presets/js-with-ts' + else { + // try to detect what transformer the js extensions would target + const jsTransformers = Object.keys(migratedConfig.transform || {}).reduce( + (list, pattern) => { + if (RegExp(pattern.replace(/^\/?/, '/dummy-project/')).test('/dummy-project/src/foo.js')) { + let transformer: string = (migratedConfig.transform as any)[pattern] + if (/\bbabel-jest\b/.test(transformer)) transformer = 'babel-jest' + else if (/\ts-jest\b/.test(transformer)) transformer = 'ts-jest' + return [...list, transformer] + } + return list + }, + [] as string[], + ) + // depending on the transformer found, we use one or the other preset + const jsWithTs = jsTransformers.includes('ts-jest') + const jsWithBabel = jsTransformers.includes('babel-jest') + if (jsWithBabel && !jsWithTs) { + presetName = 'ts-jest/presets/js-with-babel' + } else if (jsWithTs && !jsWithBabel) { + presetName = 'ts-jest/presets/js-with-ts' + } else { + // sounds like js files are NOT handled, or handled with a unknown transformer, so we do not need to handle it + presetName = DEFAULT_PRESET + } + } + // ensure we are using a preset + presetName = presetName || DEFAULT_PRESET + migratedConfig.preset = presetName + footNotes.push( + `Detected preset '${presetName.replace( + /^ts-jest\/presets\//, + '', + )}' as the best matching preset for your configuration.\nVisit https://kulshekhar.github.io/ts-jest/user/config/#jest-preset for more information about presets.\n`, + ) + } else if (migratedConfig.preset && migratedConfig.preset.startsWith('ts-jest')) { + if (args.jestPreset === false) { + delete migratedConfig.preset + } else { + presetName = migratedConfig.preset + } } - const usesPreset = migratedConfig.preset === 'ts-jest' - const presets = createJestPreset({ allowJs: args.allowJs }) + const presets: TsJestPresets | undefined = presetName + ? require(`../../../${presetName.replace(/^ts-jest\//, '')}/jest-preset`) + : undefined // check the extensions - if (migratedConfig.moduleFileExtensions && migratedConfig.moduleFileExtensions.length && usesPreset) { + if (migratedConfig.moduleFileExtensions && migratedConfig.moduleFileExtensions.length && presets) { const presetValue = dedupSort(presets.moduleFileExtensions).join('::') const migratedValue = dedupSort(migratedConfig.moduleFileExtensions).join('::') if (presetValue === migratedValue) { @@ -51,11 +96,11 @@ export const run: CliCommand = async (args: Arguments /*, logger: Logger*/) => { } } // there is a testRegex, remove our testMatch - if (migratedConfig.testRegex && usesPreset) { + if (migratedConfig.testRegex && presets) { migratedConfig.testMatch = null as any } // check the testMatch - else if (migratedConfig.testMatch && migratedConfig.testMatch.length && usesPreset) { + else if (migratedConfig.testMatch && migratedConfig.testMatch.length && presets) { const presetValue = dedupSort(presets.testMatch).join('::') const migratedValue = dedupSort(migratedConfig.testMatch).join('::') if (presetValue === migratedValue) { @@ -75,7 +120,7 @@ export const run: CliCommand = async (args: Arguments /*, logger: Logger*/) => { } // check if it's the same as the preset's one if ( - usesPreset && + presets && migratedConfig.transform && stringifyJson(migratedConfig.transform) === stringifyJson(presets.transform) ) { @@ -95,7 +140,7 @@ No migration needed for given Jest configuration } const stringify = /\.json$/.test(file) ? JSON.stringify : stringifyJson5 - const footNotes: string[] = [] + const prefix = /\.json$/.test(file) ? '"jest": ' : 'module.exports = ' // if we are using preset, inform the user that he might be able to remove some section(s) // we couldn't check for equality @@ -109,7 +154,7 @@ No migration needed for given Jest configuration // If it is the case, you can safely remove the "testMatch" from what I've migrated. // `) // } - if (usesPreset && migratedConfig.transform) { + if (presets && migratedConfig.transform) { footNotes.push(` I couldn't check if your "transform" value is the same as mine which is: ${stringify( presets.transform, @@ -124,7 +169,7 @@ If it is the case, you can safely remove the "transform" from what I've migrated process.stderr.write(` Migrated Jest configuration: `) - process.stdout.write(`${stringify(migratedConfig, undefined, ' ')}\n`) + process.stdout.write(`${prefix}${stringify(migratedConfig, undefined, ' ')}\n`) if (footNotes.length) { process.stderr.write(` ${footNotes.join('\n')} @@ -152,6 +197,7 @@ function cleanupConfig(config: jest.InitialOptions): void { config.testMatch = dedupSort(config.testMatch) if (config.testMatch.length === 0) delete config.testMatch } + if (config.preset === DEFAULT_PRESET) config.preset = 'ts-jest' } function dedupSort(arr: any[]) { From 6a72a876798d5edecb6a7fa7964e7c32901e1524 Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Tue, 25 Sep 2018 11:30:54 +0200 Subject: [PATCH 7/9] test(cli): test migrate preset detection --- src/cli/cli.spec.ts | 106 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 16 deletions(-) diff --git a/src/cli/cli.spec.ts b/src/cli/cli.spec.ts index da4164ff01..d555281317 100644 --- a/src/cli/cli.spec.ts +++ b/src/cli/cli.spec.ts @@ -1,9 +1,7 @@ -import { testing } from 'bs-logger' import * as _fs from 'fs' import { normalize, resolve } from 'path' -import { mockObject, mockWriteStream, mocked } from '../__helpers__/mocks' -import { rootLogger as _rootLogger } from '../util/logger' +import { logTargetMock, mockObject, mockWriteStream, mocked } from '../__helpers__/mocks' import { processArgv } from '.' @@ -11,7 +9,7 @@ import { processArgv } from '.' jest.mock('fs') const fs = mocked(_fs) -const rootLogger = _rootLogger as testing.LoggerMock +const logTarget = logTargetMock() let lastExitCode: number | undefined const runCli = async ( @@ -19,7 +17,7 @@ const runCli = async ( ): Promise<{ stdout: string; stderr: string; exitCode: number | undefined; log: string }> => { mockedProcess.stderr.clear() mockedProcess.stdout.clear() - rootLogger.target.clear() + logTarget.clear() mockedProcess.argv.splice(2, mockedProcess.argv.length - 2, ...args) lastExitCode = undefined await processArgv() @@ -27,7 +25,7 @@ const runCli = async ( exitCode: lastExitCode, stdout: mockedProcess.stdout.written.join('\n'), stderr: mockedProcess.stderr.written.join('\n'), - log: rootLogger.target.lines.join('\n'), + log: logTarget.lines.join('\n'), } } @@ -56,7 +54,7 @@ beforeEach(() => { fs.writeFileSync.mockClear() fs.existsSync.mockClear() fs.readFileSync.mockClear() - rootLogger.target.clear() + logTarget.clear() }) afterEach(() => { mockedProcess.mockRestore() @@ -274,12 +272,19 @@ Options: describe('migrate', async () => { const pkgPaths = { _id: 0, + _cfgId: 0, get next() { return `./foo/${++pkgPaths._id}/package.json` }, get current() { return `./foo/${pkgPaths._id}/package.json` }, + get nextCfg() { + return `./foo/${pkgPaths._id}/jest.config.${++pkgPaths._cfgId}.js` + }, + get currentCfg() { + return `./foo/${pkgPaths._id}/jest.config.${pkgPaths._cfgId}.js` + }, } const noOption = ['config:migrate'] const fullOptions = [...noOption, '--no-jest-preset', '--allow-js'] @@ -315,12 +320,16 @@ Options: expect(res).toMatchInlineSnapshot(` Object { "exitCode": 0, - "log": "[level:20] creating jest presets not handling JavaScript files -", + "log": "", "stderr": " Migrated Jest configuration: + + +Detected preset 'default' as the best matching preset for your configuration. +Visit https://kulshekhar.github.io/ts-jest/user/config/#jest-preset for more information about presets. + ", - "stdout": "{ + "stdout": "\\"jest\\": { \\"globals\\": { \\"ts-jest\\": { \\"tsConfig\\": { @@ -350,12 +359,11 @@ Migrated Jest configuration: expect(res).toMatchInlineSnapshot(` Object { "exitCode": 0, - "log": "[level:20] creating jest presets handling JavaScript files -", + "log": "", "stderr": " Migrated Jest configuration: ", - "stdout": "{ + "stdout": "\\"jest\\": { \\"globals\\": { \\"ts-jest\\": { \\"tsConfig\\": { @@ -391,7 +399,7 @@ Migrated Jest configuration: ) const res = await runCli(...noOption, pkgPaths.current) expect(res.stdout).toMatchInlineSnapshot(` -"{ +"\\"jest\\": { \\"globals\\": { \\"ts-jest\\": { \\"tsConfig\\": { @@ -419,7 +427,7 @@ Migrated Jest configuration: ) const res = await runCli(...noOption, pkgPaths.current) expect(res.stdout).toMatchInlineSnapshot(` -"{ +"\\"jest\\": { \\"testRegex\\": \\"foo-pattern\\", \\"preset\\": \\"ts-jest\\", \\"testMatch\\": null @@ -428,6 +436,72 @@ Migrated Jest configuration: `) }) + it('should detect best preset', async () => { + expect.assertions(5) + fs.existsSync.mockImplementation(() => true) + jest.mock(pkgPaths.next, () => ({}), { virtual: true }) + + // defaults + jest.doMock(pkgPaths.nextCfg, () => ({}), { virtual: true }) + let res = await runCli(...noOption, pkgPaths.currentCfg) + expect(res.stdout).toMatchInlineSnapshot(` +"module.exports = { + preset: 'ts-jest', +} +" +`) + + // js-with-ts from args + jest.doMock(pkgPaths.nextCfg, () => ({}), { virtual: true }) + res = await runCli(...noOption, '--allow-js', pkgPaths.currentCfg) + expect(res.stdout).toMatchInlineSnapshot(` +"module.exports = { + preset: 'ts-jest/presets/js-with-ts', +} +" +`) + + // js-with-ts from previous transform + jest.doMock(pkgPaths.nextCfg, () => ({ transform: { '^.+\\.[tj]sx?$': 'ts-jest' } }), { virtual: true }) + res = await runCli(...noOption, pkgPaths.currentCfg) + expect(res.stdout).toMatchInlineSnapshot(` +"module.exports = { + preset: 'ts-jest/presets/js-with-ts', +} +" +`) + + // js-with-babel from previous transform + jest.doMock(pkgPaths.nextCfg, () => ({ transform: { '^.+\\.jsx?$': 'babel-jest', '^.+\\.tsx?$': 'ts-jest' } }), { + virtual: true, + }) + res = await runCli(...noOption, pkgPaths.currentCfg) + expect(res.stdout).toMatchInlineSnapshot(` +"module.exports = { + preset: 'ts-jest/presets/js-with-babel', +} +" +`) + + // defaults when previous transform is ambiguous + jest.doMock( + pkgPaths.nextCfg, + () => ({ transform: { '^src/js/.+\\.jsx?$': 'babel-jest', '^src/ts/.+\\.tsx?$': 'ts-jest' } }), + { virtual: true }, + ) + res = await runCli(...noOption, pkgPaths.currentCfg) + expect(res.stdout).toMatchInlineSnapshot(` +"module.exports = { + transform: { + '^src/js/.+\\\\\\\\.jsx?$': 'babel-jest', + '^src/ts/.+\\\\\\\\.tsx?$': 'ts-jest', + }, + preset: 'ts-jest', +} +" +`) + }) + it('should normalize transform values', async () => { expect.assertions(1) fs.existsSync.mockImplementation(() => true) @@ -446,7 +520,7 @@ Migrated Jest configuration: ) const res = await runCli(...noOption, pkgPaths.current) expect(res.stdout).toMatchInlineSnapshot(` -"{ +"\\"jest\\": { \\"transform\\": { \\"/src/.+\\\\\\\\.[jt]s$\\": \\"ts-jest\\", \\"foo\\\\\\\\.ts\\": \\"ts-jest\\", From ddc2f79a11af8cc50c592c34672663a4568552d4 Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Tue, 25 Sep 2018 18:39:38 +0200 Subject: [PATCH 8/9] docs(preset): usage of all presets + note about testMatch --- docs/user/config/index.md | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/user/config/index.md b/docs/user/config/index.md index 95d25e165c..0b8d3ad9d7 100644 --- a/docs/user/config/index.md +++ b/docs/user/config/index.md @@ -6,9 +6,19 @@ The later is preferred since it's more customizable, but it depends on your need ## Jest preset +### The 3 presets + +`ts-jest` comes with 3 presets, allowing to cover most of project's base configuration: + +| Preset name | Description | +|---|---| +| `ts-jest/presets/default`
or `ts-jest` | `ts-jest` will take care of `.ts` and `.tsx` files only, leaving JavaScript files as-is. | +| `ts-jest/presets/js-with-ts` | TypeScript and JavaScript file (`.ts`, `.tsx`, `.js` and `.jsx`) will be handled by `ts-jest` (and so TypeScript).
You'll need to set `allowJs` to `true` in your `tsconfig.json` file. | +| `ts-jest/presets/js-with-babel` | TypeScript files will be handled by `ts-jest`, and JavaScript files will be handled by `babel-jest`. | + ### Basic usage -In most cases, simply adding `preset: 'ts-jest'` to your Jest config should be enough to start using TypeScript with Jest (assuming you did add `ts-jest` to your dev. dependencies of course): +In most cases, simply setting the `preset` key to the desired preset name in your Jest config should be enough to start using TypeScript with Jest (assuming you did add `ts-jest` to your dev. dependencies of course):
@@ -16,6 +26,8 @@ In most cases, simply adding `preset: 'ts-jest'` to your Jest config should be e // jest.config.js module.exports = { // [...] + // Replace `ts-jest` with the preset you want to use + // from the above list preset: 'ts-jest' }; ``` @@ -27,6 +39,8 @@ module.exports = { { // [...] "jest": { + // Replace `ts-jest` with the preset you want to use + // from the above list "preset": "ts-jest" } } @@ -34,20 +48,26 @@ module.exports = {
+**Note:** presets are using `testMatch`, as Jest's does in its defaults. If you want to use `testRegex` instead in your configuration, you MUST set `testMatch` to `null` or Jest will bail. + ### Advanced -The `ts-jest` preset can also be used with other options. -If you're already using another preset, you might want only some specific settings from the `ts-jest` preset. +Any preset can also be used with other options. +If you're already using another preset, you might want only some specific settings from the `ts-jest` chosen preset. In this case you'll need to use the JavaScript version of Jest config: ```js // jest.config.js -const { jestPreset: tsJestPreset } = require('ts-jest'); +const tsJestPresets = require('ts-jest/presets'); + +const preset = tsJestPresets.defaults +// const preset = tsJestPresets.jsWithTs +// const preset = tsJestPresets.jsWithBabel module.exports = { // [...] transform: { - ...tsJestPreset.transform, + ...preset.transform, // [...] } } From a4bbdcd2238e82d2ab4d1375d1b64d7e9ce12d13 Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Tue, 25 Sep 2018 23:06:59 +0200 Subject: [PATCH 9/9] docs(preset): typos --- docs/user/config/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/user/config/index.md b/docs/user/config/index.md index 0b8d3ad9d7..b385353a25 100644 --- a/docs/user/config/index.md +++ b/docs/user/config/index.md @@ -8,12 +8,12 @@ The later is preferred since it's more customizable, but it depends on your need ### The 3 presets -`ts-jest` comes with 3 presets, allowing to cover most of project's base configuration: +`ts-jest` comes with 3 presets, covering most of project's base configuration: | Preset name | Description | |---|---| | `ts-jest/presets/default`
or `ts-jest` | `ts-jest` will take care of `.ts` and `.tsx` files only, leaving JavaScript files as-is. | -| `ts-jest/presets/js-with-ts` | TypeScript and JavaScript file (`.ts`, `.tsx`, `.js` and `.jsx`) will be handled by `ts-jest` (and so TypeScript).
You'll need to set `allowJs` to `true` in your `tsconfig.json` file. | +| `ts-jest/presets/js-with-ts` | TypeScript and JavaScript file (`.ts`, `.tsx`, `.js` and `.jsx`) will be handled by `ts-jest`.
You'll need to set `allowJs` to `true` in your `tsconfig.json` file. | | `ts-jest/presets/js-with-babel` | TypeScript files will be handled by `ts-jest`, and JavaScript files will be handled by `babel-jest`. | ### Basic usage @@ -48,12 +48,12 @@ module.exports = { -**Note:** presets are using `testMatch`, as Jest's does in its defaults. If you want to use `testRegex` instead in your configuration, you MUST set `testMatch` to `null` or Jest will bail. +**Note:** presets use `testMatch`, like Jest does in its defaults. If you want to use `testRegex` instead in your configuration, you MUST set `testMatch` to `null` or Jest will bail. ### Advanced Any preset can also be used with other options. -If you're already using another preset, you might want only some specific settings from the `ts-jest` chosen preset. +If you're already using another preset, you might want only some specific settings from the chosen `ts-jest` preset. In this case you'll need to use the JavaScript version of Jest config: ```js