diff --git a/.eslintrc.js b/.eslintrc.js index d1ecc65ea7..e00b96a15a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,6 +7,9 @@ module.exports = { ecmaVersion: 2020, sourceType: 'module', impliedStrict: true, + ecmaFeatures: { + jsx: true, + }, }, rules: { 'no-console': ['error', { allow: ['warn', 'error', 'log'] }], diff --git a/CHANGELOG.md b/CHANGELOG.md index af3fcaeb4f..8e31f241c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -# [25.2.1](https://github.com/kulshekhar/ts-jest/compare/25.2.1...25.2.0) (2020-02-21) +# [25.2.1](https://github.com/kulshekhar/ts-jest/compare/25.2.0...25.2.1) (2020-02-21) ### Bug Fixes diff --git a/docs/user/config/compilerHost.md b/docs/user/config/compilerHost.md new file mode 100644 index 0000000000..8bc398c47a --- /dev/null +++ b/docs/user/config/compilerHost.md @@ -0,0 +1,93 @@ +--- +title: Compiler Host option +--- + +By default `ts-jest` uses TypeScript `LanguageService` API in the context of a project (yours), with full type-checking and features. +But TypeScript `Program` can also be used to achieve the same behavior as `LanguageService`. +That's what the `compilerHost` option (which defaults to `false`) does. + +There are 2 types of TypeScript `Program`, one is `Incremental Program` which is only available from TypeScript 3.4 +and the other one is normal `Program`. + +By default `ts-jest` uses `Incremental Program` if `compilerHost` is enabled. The priority of using TypeScript APIs in `ts-jest` +as below: +- Default TypeScript API is `LanguageService`. +- `compilerHost` is enabled: + - `incremental` is enabled (**default**): use TypeScript `Incremental Program`. + - `incremental` is disabled: use TypeScript `Program`. +- `isolatedModules` is enabled, use TypeScript transpile modules. + +Here is how to enable `ts-jest` to compile using TypeScript `Program` + +### Example + +
+ +```js +// jest.config.js +module.exports = { + // [...] + globals: { + 'ts-jest': { + compilerHost: true, + incremental: false, + } + } +}; +``` + +
+ +```js +// OR package.json +{ + // [...] + "jest": { + "globals": { + "ts-jest": { + "compilerHost": true, + "incremental": false + } + } + } +} +``` + +
+ + +Here is how to enable `ts-jest` to compile using TypeScript `IncrementalProgram` + +### Example + +
+ +```js +// jest.config.js +module.exports = { + // [...] + globals: { + 'ts-jest': { + compilerHost: true + } + } +}; +``` + +
+ +```js +// OR package.json +{ + // [...] + "jest": { + "globals": { + "ts-jest": { + "compilerHost": true + } + } + } +} +``` + +
diff --git a/docs/user/config/index.md b/docs/user/config/index.md index 7d7eda3bd8..c7ee515358 100644 --- a/docs/user/config/index.md +++ b/docs/user/config/index.md @@ -220,6 +220,7 @@ npx ts-jest config:migrate package.json [compiler]: compiler [tsConfig]: tsConfig [isolatedModules]: isolatedModules +[compilerHost]: compilerHost [diagnostics]: diagnostics [babelConfig]: babelConfig [stringifyContentPathRegex]: stringifyContentPathRegex diff --git a/e2e/__cases__/compiler-host/main.spec.ts b/e2e/__cases__/compiler-host/main.spec.ts new file mode 100644 index 0000000000..04bff66dc8 --- /dev/null +++ b/e2e/__cases__/compiler-host/main.spec.ts @@ -0,0 +1,6 @@ +import { g } from './main' + +it('should pass', () => { + const x: string = g(5) + expect(x).toBe(5) +}) diff --git a/e2e/__cases__/compiler-host/main.ts b/e2e/__cases__/compiler-host/main.ts new file mode 100644 index 0000000000..62b8101c36 --- /dev/null +++ b/e2e/__cases__/compiler-host/main.ts @@ -0,0 +1 @@ +export const g = (v: number) => v diff --git a/e2e/__cases__/composite/foo.spec.ts b/e2e/__cases__/composite/foo.spec.ts deleted file mode 100644 index 5c772cc97d..0000000000 --- a/e2e/__cases__/composite/foo.spec.ts +++ /dev/null @@ -1,3 +0,0 @@ -test('foo', () => { - expect(true).toBeTruthy(); -}); diff --git a/e2e/__cases__/composite/tsconfig.json b/e2e/__cases__/composite/tsconfig.json deleted file mode 100644 index 6680bc4fe6..0000000000 --- a/e2e/__cases__/composite/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "tsBuildInfoFile": ".tsbuildinfo" - } -} diff --git a/e2e/__helpers__/templates.ts b/e2e/__helpers__/templates.ts index bc0200d235..ff20228f6b 100644 --- a/e2e/__helpers__/templates.ts +++ b/e2e/__helpers__/templates.ts @@ -6,5 +6,7 @@ export enum PackageSets { // invalid unsupportedVersion = 'with-unsupported-version', } -export const allValidPackageSets = [PackageSets.default, PackageSets.babel7, PackageSets.babel7StringConfig, PackageSets.typescript2_7] -export const allPackageSetsWithPreset = [PackageSets.default, PackageSets.babel7, PackageSets.babel7StringConfig, PackageSets.typescript2_7] +export const allValidPackageSets = [PackageSets.default, PackageSets.babel7, PackageSets.babel7StringConfig, PackageSets.typescript2_7], + allPackageSetsWithPreset = [PackageSets.default, PackageSets.babel7, PackageSets.babel7StringConfig, PackageSets.typescript2_7], + allPackageSetsWithProgram = [PackageSets.default, PackageSets.babel7, PackageSets.babel7StringConfig], + allPackageSetsWithoutProgram = [PackageSets.typescript2_7, PackageSets.unsupportedVersion] diff --git a/e2e/__monorepos__/simple/with-dependency/package.json b/e2e/__monorepos__/simple/with-dependency/package.json index 1f4d55b21a..d636e4c7bf 100644 --- a/e2e/__monorepos__/simple/with-dependency/package.json +++ b/e2e/__monorepos__/simple/with-dependency/package.json @@ -32,7 +32,8 @@ "ts-jest": { "diagnostics": true, "tsConfig": "/tsconfig.json", - "compilerHost": true + "compilerHost": true, + "incremental": true } } }, diff --git a/e2e/__monorepos__/simple/with-dependency/tsconfig.json b/e2e/__monorepos__/simple/with-dependency/tsconfig.json index 65f41ccd82..e2a32abfa8 100644 --- a/e2e/__monorepos__/simple/with-dependency/tsconfig.json +++ b/e2e/__monorepos__/simple/with-dependency/tsconfig.json @@ -13,8 +13,7 @@ "downlevelIteration": true, "strict": true, "moduleResolution": "node", - "esModuleInterop": true, - "incremental": true + "esModuleInterop": true }, "include": [ "./src" diff --git a/e2e/__tests__/__snapshots__/compiler-host.test.ts.snap b/e2e/__tests__/__snapshots__/compiler-host.test.ts.snap new file mode 100644 index 0000000000..7418daca91 --- /dev/null +++ b/e2e/__tests__/__snapshots__/compiler-host.test.ts.snap @@ -0,0 +1,219 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`With compilerHost enabled and incremental disabled should fail using template "with-typescript-2-7" 1`] = ` + × jest --no-cache + ↳ exit code: 1 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + FAIL ./main.spec.ts + ● Test suite failed to run + + TypeError: Cannot read property 'maxNodeModuleJsDepth' of undefined + + at Object.createProgram (../../__templates__/with-typescript-2-7/node_modules/typescript/lib/typescript.js:73929:51) + + Test Suites: 1 failed, 1 total + Tests: 0 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental disabled should fail using template "with-unsupported-version" 1`] = ` + × jest --no-cache + ↳ exit code: 1 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + ts-jest[versions] (WARN) Version 2.5.3 of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. + FAIL ./main.spec.ts + ● Test suite failed to run + + TypeError: Cannot read property 'maxNodeModuleJsDepth' of undefined + + at Object.createProgram (../../__templates__/with-unsupported-version/node_modules/typescript/lib/typescript.js:69709:51) + + Test Suites: 1 failed, 1 total + Tests: 0 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental disabled should pass using template "default" 1`] = ` + √ jest --no-cache + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) TypeScript diagnostics (customize using \`[jest-config].globals.ts-jest.diagnostics\` option): + main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + + 4 const x: string = g(5) + ~ + PASS ./main.spec.ts + √ should pass + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental disabled should pass using template "with-babel-7" 1`] = ` + √ jest --no-cache + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) TypeScript diagnostics (customize using \`[jest-config].globals.ts-jest.diagnostics\` option): + main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + + 4 const x: string = g(5) + ~ + PASS ./main.spec.ts + √ should pass + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental disabled should pass using template "with-babel-7-string-config" 1`] = ` + √ jest --no-cache + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) TypeScript diagnostics (customize using \`[jest-config].globals.ts-jest.diagnostics\` option): + main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + + 4 const x: string = g(5) + ~ + PASS ./main.spec.ts + √ should pass + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental enabled should fail using template "with-typescript-2-7" 1`] = ` + × jest --no-cache + ↳ exit code: 1 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + FAIL ./main.spec.ts + ● Test suite failed to run + + TypeError: Cannot read property 'maxNodeModuleJsDepth' of undefined + + at Object.createProgram (../../__templates__/with-typescript-2-7/node_modules/typescript/lib/typescript.js:73929:51) + + Test Suites: 1 failed, 1 total + Tests: 0 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental enabled should fail using template "with-unsupported-version" 1`] = ` + × jest --no-cache + ↳ exit code: 1 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + ts-jest[versions] (WARN) Version 2.5.3 of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. + FAIL ./main.spec.ts + ● Test suite failed to run + + TypeError: Cannot read property 'maxNodeModuleJsDepth' of undefined + + at Object.createProgram (../../__templates__/with-unsupported-version/node_modules/typescript/lib/typescript.js:69709:51) + + Test Suites: 1 failed, 1 total + Tests: 0 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental enabled should pass using template "default" 1`] = ` + √ jest --no-cache + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) TypeScript diagnostics (customize using \`[jest-config].globals.ts-jest.diagnostics\` option): + main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + + 4 const x: string = g(5) + ~ + PASS ./main.spec.ts + √ should pass + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental enabled should pass using template "with-babel-7" 1`] = ` + √ jest --no-cache + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) TypeScript diagnostics (customize using \`[jest-config].globals.ts-jest.diagnostics\` option): + main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + + 4 const x: string = g(5) + ~ + PASS ./main.spec.ts + √ should pass + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With compilerHost enabled and incremental enabled should pass using template "with-babel-7-string-config" 1`] = ` + √ jest --no-cache + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) TypeScript diagnostics (customize using \`[jest-config].globals.ts-jest.diagnostics\` option): + main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + + 4 const x: string = g(5) + ~ + PASS ./main.spec.ts + √ should pass + + 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__/compiler-host.test.ts b/e2e/__tests__/compiler-host.test.ts new file mode 100644 index 0000000000..21625f4b8d --- /dev/null +++ b/e2e/__tests__/compiler-host.test.ts @@ -0,0 +1,52 @@ +import { allPackageSetsWithProgram, allPackageSetsWithoutProgram } from '../__helpers__/templates' +import { configureTestCase } from '../__helpers__/test-case' + +describe('With compilerHost enabled and incremental disabled', () => { + const testCase = configureTestCase('compiler-host', { + tsJestConfig: { compilerHost: true, incremental: false, diagnostics: { warnOnly: true } }, + noCache: true, + }) + + testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { + it(testLabel, () => { + // tslint:disable-next-line:no-console + console.log = jest.fn() + const result = runTest() + expect(result.status).toBe(0) + expect(result).toMatchSnapshot() + }) + }) + + testCase.runWithTemplates(allPackageSetsWithoutProgram, 1, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(1) + expect(result).toMatchSnapshot() + }) + }) +}) + +describe('With compilerHost enabled and incremental enabled', () => { + const testCase = configureTestCase('compiler-host', { + tsJestConfig: { compilerHost: true, incremental: false, diagnostics: { warnOnly: true } }, + noCache: true, + }) + + testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { + it(testLabel, () => { + // tslint:disable-next-line:no-console + console.log = jest.fn() + const result = runTest() + expect(result.status).toBe(0) + expect(result).toMatchSnapshot() + }) + }) + + testCase.runWithTemplates(allPackageSetsWithoutProgram, 1, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(1) + expect(result).toMatchSnapshot() + }) + }) +}) diff --git a/e2e/__tests__/composite.test.ts b/e2e/__tests__/composite.test.ts deleted file mode 100644 index f2c3bfd874..0000000000 --- a/e2e/__tests__/composite.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { PackageSets } from '../__helpers__/templates' -import { configureTestCase } from '../__helpers__/test-case' - -describe('with composite enabled', () => { - const testCase = configureTestCase('composite') - - testCase.runWithTemplates([PackageSets.default], 0, (runTest, { testLabel }) => { - it(testLabel, () => { - const result = runTest() - expect(result.status).toBe(0) - }) - }) -}) diff --git a/jest.config.js b/jest.config.js index deb6d6ae4c..9b6a9ccd93 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,6 +11,7 @@ module.exports = { '!/src/**/*.spec.ts', '!/src/**/*.test.ts', '!/src/**/__*__/*', + '!/src/util/testing.ts', ], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], testEnvironment: 'node', diff --git a/src/__helpers__/fakers.ts b/src/__helpers__/fakers.ts index c2e23369a6..483f91e762 100644 --- a/src/__helpers__/fakers.ts +++ b/src/__helpers__/fakers.ts @@ -16,6 +16,7 @@ export function tsJestConfig(options?: Partial): TsJestConfig { return { compilerHost: false, emit: false, + incremental: false, isolatedModules: false, compiler: 'typescript', transformers: [], diff --git a/src/__mocks__/tsconfig.json b/src/__mocks__/tsconfig.json new file mode 100644 index 0000000000..191e175490 --- /dev/null +++ b/src/__mocks__/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "jsx": "preserve", + "outDir": "$$ts-jest$$" + } +} diff --git a/src/compiler/__snapshots__/language-service.spec.ts.snap b/src/compiler/__snapshots__/language-service.spec.ts.snap index f12e0f2048..dfe4494771 100644 --- a/src/compiler/__snapshots__/language-service.spec.ts.snap +++ b/src/compiler/__snapshots__/language-service.spec.ts.snap @@ -1,38 +1,66 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`language service should compile js file for allowJs true 1`] = ` - ===[ FILE: foo.test.js ]======================================================== + ===[ FILE: test-allow-js.js ]=================================================== "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = 42; - //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiZm9vLnRlc3QuanMiLCJtYXBwaW5ncyI6Ijs7QUFBQSxrQkFBZSxFQUFFLENBQUEiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiZm9vLnRlc3QuanMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGRlZmF1bHQgNDIiXSwidmVyc2lvbiI6M30= + //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoidGVzdC1hbGxvdy1qcy5qcyIsIm1hcHBpbmdzIjoiOztBQUFBLGtCQUFlLEVBQUUsQ0FBQSIsIm5hbWVzIjpbXSwic291cmNlcyI6WyJ0ZXN0LWFsbG93LWpzLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBkZWZhdWx0IDQyIl0sInZlcnNpb24iOjN9 ===[ INLINE SOURCE MAPS ]======================================================= - file: foo.test.js + file: test-allow-js.js mappings: ';;AAAA,kBAAe,EAAE,CAAA' names: [] sources: - - foo.test.js + - test-allow-js.js sourcesContent: - export default 42 version: 3 ================================================================================ `; +exports[`language service should compile tsx file for jsx preserve 1`] = ` + ===[ FILE: test-jsx-preserve.tsx ]============================================== + var App = function () { + return <>Test; + }; + //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoidGVzdC1qc3gtcHJlc2VydmUudHN4IiwibWFwcGluZ3MiOiJBQUNRLElBQU0sR0FBRyxHQUFHO0lBQ1YsT0FBTyxFQUFFLElBQUksR0FBRyxDQUFBO0FBQ2xCLENBQUMsQ0FBQSIsIm5hbWVzIjpbXSwic291cmNlcyI6WyJ0ZXN0LWpzeC1wcmVzZXJ2ZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiXG4gICAgICAgIGNvbnN0IEFwcCA9ICgpID0+IHtcbiAgICAgICAgICByZXR1cm4gPD5UZXN0PC8+XG4gICAgICAgIH1cbiAgICAgICJdLCJ2ZXJzaW9uIjozfQ== + ===[ INLINE SOURCE MAPS ]======================================================= + file: test-jsx-preserve.tsx + mappings: 'AACQ,IAAM,GAAG,GAAG;IACV,OAAO,EAAE,IAAI,GAAG,CAAA;AAClB,CAAC,CAAA' + names: [] + sources: + - test-jsx-preserve.tsx + sourcesContent: + - |2- + + const App = () => { + return <>Test + } + + version: 3 + ================================================================================ +`; + exports[`language service should report diagnostics related to typings with pathRegex config matches file name 1`] = ` "TypeScript diagnostics (customize using \`[jest-config].globals.ts-jest.diagnostics\` option): -foo.ts(3,7): error TS2322: Type 'number' is not assignable to type 'string'." +test-match-regex-diagnostics.ts(3,7): error TS2322: Type 'number' is not assignable to type 'string'." +`; + +exports[`language service should throw error when cannot compile 1`] = ` +"Unable to require \`.d.ts\` file for file: test-cannot-compile.d.ts. +This is usually the result of a faulty configuration or import. Make sure there is a \`.js\`, \`.json\` or another executable extension available alongside \`test-cannot-compile.d.ts\`." `; exports[`language service should use the cache 3`] = ` - ===[ FILE: src/compiler/language-service.spec.ts ]============================== + ===[ FILE: test-cache.ts ]====================================================== console.log("hello"); - //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiPGN3ZD4vc3JjL2NvbXBpbGVyL2xhbmd1YWdlLXNlcnZpY2Uuc3BlYy50cyIsIm1hcHBpbmdzIjoiQUFBQSxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFBIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIjxjd2Q+L3NyYy9jb21waWxlci9sYW5ndWFnZS1zZXJ2aWNlLnNwZWMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiY29uc29sZS5sb2coXCJoZWxsb1wiKSJdLCJ2ZXJzaW9uIjozfQ== + //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoidGVzdC1jYWNoZS50cyIsIm1hcHBpbmdzIjoiQUFBQSxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFBIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbInRlc3QtY2FjaGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiY29uc29sZS5sb2coXCJoZWxsb1wiKSJdLCJ2ZXJzaW9uIjozfQ== ===[ INLINE SOURCE MAPS ]======================================================= - file: /src/compiler/language-service.spec.ts + file: test-cache.ts mappings: 'AAAA,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA' names: [] sources: - - /src/compiler/language-service.spec.ts + - test-cache.ts sourcesContent: - console.log("hello") version: 3 diff --git a/src/compiler/__snapshots__/program.spec.ts.snap b/src/compiler/__snapshots__/program.spec.ts.snap index 9dad9a5468..a1d3e3bf83 100644 --- a/src/compiler/__snapshots__/program.spec.ts.snap +++ b/src/compiler/__snapshots__/program.spec.ts.snap @@ -36,6 +36,62 @@ exports[`allowJs should compile js file for allowJs true with normal program 1`] ================================================================================ `; +exports[`cannot compile should throw error with incremental program 1`] = ` +"Unable to require \`.d.ts\` file for file: test-cannot-compile.d.ts. +This is usually the result of a faulty configuration or import. Make sure there is a \`.js\`, \`.json\` or another executable extension available alongside \`test-cannot-compile.d.ts\`." +`; + +exports[`cannot compile should throw error with normal program 1`] = ` +"Unable to require \`.d.ts\` file for file: test-cannot-compile.d.ts. +This is usually the result of a faulty configuration or import. Make sure there is a \`.js\`, \`.json\` or another executable extension available alongside \`test-cannot-compile.d.ts\`." +`; + +exports[`jsx preserve should compile tsx file for jsx preserve with incremental program 1`] = ` + ===[ FILE: test-jsx-preserve.tsx ]============================================== + var App = function () { + return <>Test; + }; + //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoidGVzdC1qc3gtcHJlc2VydmUudHN4IiwibWFwcGluZ3MiOiJBQUNNLElBQU0sR0FBRyxHQUFHO0lBQ1YsT0FBTyxFQUFFLElBQUksR0FBRyxDQUFBO0FBQ2xCLENBQUMsQ0FBQSIsIm5hbWVzIjpbXSwic291cmNlcyI6WyJ0ZXN0LWpzeC1wcmVzZXJ2ZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiXG4gICAgICBjb25zdCBBcHAgPSAoKSA9PiB7XG4gICAgICAgIHJldHVybiA8PlRlc3Q8Lz5cbiAgICAgIH1cbiAgICAiXSwidmVyc2lvbiI6M30= + ===[ INLINE SOURCE MAPS ]======================================================= + file: test-jsx-preserve.tsx + mappings: 'AACM,IAAM,GAAG,GAAG;IACV,OAAO,EAAE,IAAI,GAAG,CAAA;AAClB,CAAC,CAAA' + names: [] + sources: + - test-jsx-preserve.tsx + sourcesContent: + - |2- + + const App = () => { + return <>Test + } + + version: 3 + ================================================================================ +`; + +exports[`jsx preserve should compile tsx file for jsx preserve with program 1`] = ` + ===[ FILE: test-jsx-preserve.tsx ]============================================== + var App = function () { + return <>Test; + }; + //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoidGVzdC1qc3gtcHJlc2VydmUudHN4IiwibWFwcGluZ3MiOiJBQUNNLElBQU0sR0FBRyxHQUFHO0lBQ1YsT0FBTyxFQUFFLElBQUksR0FBRyxDQUFBO0FBQ2xCLENBQUMsQ0FBQSIsIm5hbWVzIjpbXSwic291cmNlcyI6WyJ0ZXN0LWpzeC1wcmVzZXJ2ZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiXG4gICAgICBjb25zdCBBcHAgPSAoKSA9PiB7XG4gICAgICAgIHJldHVybiA8PlRlc3Q8Lz5cbiAgICAgIH1cbiAgICAiXSwidmVyc2lvbiI6M30= + ===[ INLINE SOURCE MAPS ]======================================================= + file: test-jsx-preserve.tsx + mappings: 'AACM,IAAM,GAAG,GAAG;IACV,OAAO,EAAE,IAAI,GAAG,CAAA;AAClB,CAAC,CAAA' + names: [] + sources: + - test-jsx-preserve.tsx + sourcesContent: + - |2- + + const App = () => { + return <>Test + } + + version: 3 + ================================================================================ +`; + exports[`typings incremental program should report diagnostics with pathRegex config matches file name 1`] = `"test-typings.ts: Emit skipped"`; exports[`typings normal program should report diagnostics with pathRegex config matches file name 1`] = ` diff --git a/src/compiler/__snapshots__/transpile-module.spec.ts.snap b/src/compiler/__snapshots__/transpile-module.spec.ts.snap index de6e87b69b..21783324d1 100644 --- a/src/compiler/__snapshots__/transpile-module.spec.ts.snap +++ b/src/compiler/__snapshots__/transpile-module.spec.ts.snap @@ -18,6 +18,29 @@ exports[`transpile module with isolatedModule: true should compile js file for a ================================================================================ `; +exports[`transpile module with isolatedModule: true should compile tsx file for jsx preserve 1`] = ` + ===[ FILE: foo.tsx ]============================================================ + var App = function () { + return <>Test; + }; + //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiZm9vLnRzeCIsIm1hcHBpbmdzIjoiQUFDUSxJQUFNLEdBQUcsR0FBRztJQUNWLE9BQU8sRUFBRSxJQUFJLEdBQUcsQ0FBQTtBQUNsQixDQUFDLENBQUEiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiZm9vLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJcbiAgICAgICAgY29uc3QgQXBwID0gKCkgPT4ge1xuICAgICAgICAgIHJldHVybiA8PlRlc3Q8Lz5cbiAgICAgICAgfVxuICAgICAgIl0sInZlcnNpb24iOjN9 + ===[ INLINE SOURCE MAPS ]======================================================= + file: foo.tsx + mappings: 'AACQ,IAAM,GAAG,GAAG;IACV,OAAO,EAAE,IAAI,GAAG,CAAA;AAClB,CAAC,CAAA' + names: [] + sources: + - foo.tsx + sourcesContent: + - |2- + + const App = () => { + return <>Test + } + + version: 3 + ================================================================================ +`; + exports[`transpile module with isolatedModule: true should compile using transpileModule and not use cache 1`] = ` ===[ FILE: src/compiler/transpile-module.spec.ts ]============================== "use strict"; diff --git a/src/compiler/instance.ts b/src/compiler/instance.ts index b168c1ee2e..807283bb3a 100644 --- a/src/compiler/instance.ts +++ b/src/compiler/instance.ts @@ -175,11 +175,9 @@ export const createCompiler = (configs: ConfigSet): TsCompiler => { let compileResult: CompileResult if (!tsJest.isolatedModules) { // Use language services by default - if (!tsJest.compilerHost) { - compileResult = compileUsingLanguageService(configs, logger, memoryCache) - } else { - compileResult = compileUsingProgram(configs, logger, memoryCache) - } + compileResult = !tsJest.compilerHost + ? compileUsingLanguageService(configs, logger, memoryCache) + : compileUsingProgram(configs, logger, memoryCache) } else { compileResult = compileUsingTranspileModule(configs, logger) } diff --git a/src/compiler/language-service.spec.ts b/src/compiler/language-service.spec.ts index 87e3bf5e07..be00c492da 100644 --- a/src/compiler/language-service.spec.ts +++ b/src/compiler/language-service.spec.ts @@ -19,10 +19,13 @@ describe('language service', () => { jestConfig: { cache: true, cacheDirectory: tmp }, tsJestConfig: { tsConfig: false }, }), - source = 'console.log("hello")' + source = 'console.log("hello")', + fileName = 'test-cache.ts' + + writeFileSync(fileName, source, 'utf8') logTarget.clear() - const compiled1 = compiler.compile(source, __filename) + const compiled1 = compiler.compile(source, fileName) expect(logTarget.filteredLines(LogLevels.debug, Infinity)).toMatchInlineSnapshot(` Array [ @@ -44,7 +47,7 @@ describe('language service', () => { `) logTarget.clear() - const compiled2 = compiler.compile(source, __filename) + const compiled2 = compiler.compile(source, fileName) expect(logTarget.lines).toMatchInlineSnapshot(` Array [ @@ -53,12 +56,14 @@ describe('language service', () => { ] `) - expect(new ProcessedSource(compiled1, __filename)).toMatchSnapshot() + expect(new ProcessedSource(compiled1, fileName)).toMatchSnapshot() expect(compiled2).toBe(compiled1) + + removeSync(fileName) }) it('should compile js file for allowJs true', () => { - const fileName = `foo.test.js`, + const fileName = `test-allow-js.js`, compiler = makeCompiler({ tsJestConfig: { tsConfig: { allowJs: true, outDir: '$$ts-jest$$' } }, }), @@ -72,27 +77,49 @@ describe('language service', () => { removeSync(fileName) }) + it('should compile tsx file for jsx preserve', () => { + const fileName = 'test-jsx-preserve.tsx', + compiler = makeCompiler({ + tsJestConfig: { tsConfig: 'src/__mocks__/tsconfig.json' }, + }), + source = ` + const App = () => { + return <>Test + } + ` + writeFileSync(fileName, source, 'utf8') + const compiled = compiler.compile(source, fileName) + + expect(new ProcessedSource(compiled, fileName)).toMatchSnapshot() + + removeSync(fileName) + }) + it('should have correct source maps', () => { const compiler = makeCompiler({ tsJestConfig: { tsConfig: false } }), - source = 'const g = (v: number) => v\nconst h: number = g(5)' + source = 'const gsm = (v: number) => v\nconst h: number = gsm(5)', + fileName = 'test-source-map.ts' + writeFileSync(fileName, source, 'utf8') - const compiled = compiler.compile(source, 'foo.ts') + const compiled = compiler.compile(source, fileName) - expect(new ProcessedSource(compiled, 'foo.ts').outputSourceMaps).toMatchObject({ - file: 'foo.ts', - sources: ['foo.ts'], + expect(new ProcessedSource(compiled, fileName).outputSourceMaps).toMatchObject({ + file: fileName, + sources: [fileName], sourcesContent: [source], }) + + removeSync(fileName) }) it('should report diagnostics related to typings with pathRegex config matches file name', () => { - const fileName = 'foo.ts', + const fileName = 'test-match-regex-diagnostics.ts', source = ` const g = (v: number) => v const x: string = g(5) `, compiler = makeCompiler({ - tsJestConfig: { tsConfig: false, diagnostics: { pathRegex: 'foo.ts' } }, + tsJestConfig: { tsConfig: false, diagnostics: { pathRegex: fileName } }, }) writeFileSync(fileName, source, 'utf8') @@ -102,7 +129,7 @@ const x: string = g(5) }) it('should not report diagnostics related to typings with pathRegex config does not match file name', () => { - const fileName = 'foo.ts', + const fileName = 'test-non-match-regex-diagnostics.ts', source = ` const f = (v: number) => v const t: string = f(5) @@ -116,4 +143,21 @@ const t: string = f(5) removeSync(fileName) }) + + it('should throw error when cannot compile', () => { + const fileName = 'test-cannot-compile.d.ts', + source = ` + interface Foo { + a: string + } + `, + compiler = makeCompiler({ + tsJestConfig: { tsConfig: false }, + }) + writeFileSync(fileName, source, 'utf8') + + expect(() => compiler.compile(source, fileName)).toThrowErrorMatchingSnapshot() + + removeSync(fileName) + }) }) diff --git a/src/compiler/language-service.ts b/src/compiler/language-service.ts index 2f2261519d..2ba934855d 100644 --- a/src/compiler/language-service.ts +++ b/src/compiler/language-service.ts @@ -124,7 +124,6 @@ export const compileUsingLanguageService = ( previousProgram = programAfter // Throw an error when requiring `.d.ts` files. - /* istanbul ignore next (this should never happen but is kept for security) */ if (!output.outputFiles.length) { throw new TypeError( interpolate(Errors.UnableToRequireDefinitionFile, { diff --git a/src/compiler/program.spec.ts b/src/compiler/program.spec.ts index 91b8e6c988..02c2eef230 100644 --- a/src/compiler/program.spec.ts +++ b/src/compiler/program.spec.ts @@ -33,7 +33,7 @@ const t: string = f(5) const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, - tsConfig: { incremental: false }, + incremental: false, diagnostics: { pathRegex: fileName }, }, }) @@ -45,7 +45,7 @@ const t: string = f(5) const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, - tsConfig: { incremental: false }, + incremental: false, diagnostics: { pathRegex: 'foo.ts' }, }, }) @@ -63,7 +63,7 @@ const t: string = f(5) const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, - tsConfig: { incremental: true }, + incremental: true, diagnostics: { pathRegex: 'typings-error.ts' }, }, }) @@ -75,7 +75,7 @@ const t: string = f(5) const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, - tsConfig: { incremental: true }, + incremental: true, diagnostics: { pathRegex: 'foo.ts' }, }, }) @@ -105,7 +105,7 @@ describe('source-maps', () => { const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, - tsConfig: { incremental: false }, + incremental: false, }, }) @@ -122,7 +122,7 @@ describe('source-maps', () => { const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, - tsConfig: { incremental: true }, + incremental: true, }, }) @@ -137,8 +137,7 @@ describe('source-maps', () => { }) describe('cache', () => { - const tmp = tempDir('compiler'), - fileName = 'test-cache.ts', + const fileName = 'test-cache.ts', source = 'console.log("hello")' beforeAll(() => { @@ -150,13 +149,14 @@ describe('cache', () => { }) it('should use the cache with normal program', () => { - const compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { - ...baseTsJestConfig, - tsConfig: { incremental: false }, - }, - }) + const tmp = tempDir('program-compiler'), + compiler = makeCompiler({ + jestConfig: { cache: true, cacheDirectory: tmp }, + tsJestConfig: { + ...baseTsJestConfig, + incremental: false, + }, + }) logTarget.clear() const compiled1 = compiler.compile(source, fileName) @@ -187,14 +187,15 @@ describe('cache', () => { expect(compiled2).toBe(compiled1) }) - it('should use the cache with normal program', () => { - const compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { - ...baseTsJestConfig, - tsConfig: { incremental: true }, - }, - }) + it('should use the cache with incremental program', () => { + const tmp = tempDir('incremental-program-compiler'), + compiler = makeCompiler({ + jestConfig: { cache: true, cacheDirectory: tmp }, + tsJestConfig: { + ...baseTsJestConfig, + incremental: true, + }, + }) logTarget.clear() const compiled1 = compiler.compile(source, fileName) @@ -202,7 +203,7 @@ describe('cache', () => { Array [ "[level:20] readThrough(): cache miss ", - "[level:20] updateMemoryCache() for program + "[level:20] updateMemoryCache() for incremental program ", "[level:20] visitSourceFileNode(): hoisting ", @@ -228,7 +229,8 @@ Array [ describe('allowJs', () => { const fileName = 'test-allowJs.test.js', - source = 'export default 42' + source = 'export default 42', + tsConfig = { allowJs: true, outDir: '$$ts-jest$$' } beforeAll(() => { writeFileSync(fileName, source, 'utf8') @@ -240,7 +242,7 @@ describe('allowJs', () => { it('should compile js file for allowJs true with normal program', () => { const compiler = makeCompiler({ - tsJestConfig: { ...baseTsJestConfig, tsConfig: { allowJs: true, outDir: '$$ts-jest$$', incremental: false } }, + tsJestConfig: { ...baseTsJestConfig, incremental: false, tsConfig }, }) const compiled = compiler.compile(source, fileName) @@ -250,7 +252,7 @@ describe('allowJs', () => { it('should compile js file for allowJs true with incremental program', () => { const compiler = makeCompiler({ - tsJestConfig: { ...baseTsJestConfig, tsConfig: { allowJs: true, outDir: '$$ts-jest$$', incremental: true } }, + tsJestConfig: { ...baseTsJestConfig, incremental: true, tsConfig }, }) const compiled = compiler.compile(source, fileName) @@ -258,3 +260,74 @@ describe('allowJs', () => { expect(new ProcessedSource(compiled, fileName)).toMatchSnapshot() }) }) + +describe('jsx preserve', () => { + const fileName = 'test-jsx-preserve.tsx', + source = ` + const App = () => { + return <>Test + } + `, + tsConfig = 'src/__mocks__/tsconfig.json' + + beforeAll(() => { + writeFileSync(fileName, source, 'utf8') + }) + + afterAll(() => { + removeSync(fileName) + }) + + it('should compile tsx file for jsx preserve with program', () => { + const compiler = makeCompiler({ + tsJestConfig: { ...baseTsJestConfig, incremental: false, tsConfig }, + }) + + const compiled = compiler.compile(source, fileName) + + expect(new ProcessedSource(compiled, fileName)).toMatchSnapshot() + }) + + it('should compile tsx file for jsx preserve with incremental program', () => { + const compiler = makeCompiler({ + tsJestConfig: { ...baseTsJestConfig, incremental: true, tsConfig }, + }) + + const compiled = compiler.compile(source, fileName) + + expect(new ProcessedSource(compiled, fileName)).toMatchSnapshot() + }) +}) + +describe('cannot compile', () => { + const fileName = 'test-cannot-compile.d.ts', + source = ` + interface Foo { + a: string + } + ` + + beforeAll(() => { + writeFileSync(fileName, source, 'utf8') + }) + + afterAll(() => { + removeSync(fileName) + }) + + it('should throw error with normal program', () => { + const compiler = makeCompiler({ + tsJestConfig: { ...baseTsJestConfig, incremental: false, tsConfig: false }, + }) + + expect(() => compiler.compile(source, fileName)).toThrowErrorMatchingSnapshot() + }) + + it('should throw error with incremental program', () => { + const compiler = makeCompiler({ + tsJestConfig: { ...baseTsJestConfig, incremental: true, tsConfig: false }, + }) + + expect(() => compiler.compile(source, fileName)).toThrowErrorMatchingSnapshot() + }) +}) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index b7822a9c33..4cf8a1d079 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -15,7 +15,8 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa const ts = configs.compilerModule, cwd = configs.cwd, - { options, fileNames, projectReferences, errors } = configs.typescript + { options, fileNames, projectReferences, errors } = configs.typescript, + incremental = configs.tsJest.incremental const compilerHostTraceCtx = { namespace: 'ts:compilerHost', call: null, @@ -36,8 +37,9 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(), } let builderProgram: _ts.EmitAndSemanticDiagnosticsBuilderProgram, program: _ts.Program, host: _ts.CompilerHost - // Fallback for older TypeScript releases without incremental API. - if (options.incremental) { + if (incremental) { + // TODO: Find a way to trigger typescript to build project when there are project references. + // At the moment this Incremental Program doesn't work with project references host = ts.createIncrementalCompilerHost(options, sys) builderProgram = ts.createIncrementalProgram({ rootNames: fileNames.slice(), @@ -48,6 +50,7 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa }) program = builderProgram.getProgram() } else { + // Fallback for older TypeScript releases without incremental API. host = { ...sys, getSourceFile: (fileName, languageVersion) => { @@ -71,7 +74,7 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa // Read and cache custom transformers. const customTransformers = configs.tsCustomTransformers, updateMemoryCache = (contents: string, normalizedFileName: string): void => { - logger.debug({ normalizedFileName }, `updateMemoryCache() for program`) + logger.debug({ normalizedFileName }, `updateMemoryCache() for ${incremental ? 'incremental program' : 'program'}`) const fileVersion = memoryCache.versions.get(normalizedFileName) ?? 0, isFileInCache = fileVersion !== 0 @@ -84,7 +87,7 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa memoryCache.versions.set(normalizedFileName, fileVersion + 1) memoryCache.contents.set(normalizedFileName, contents) } - const sourceFile = options.incremental + const sourceFile = incremental ? builderProgram.getSourceFile(normalizedFileName) : program.getSourceFile(normalizedFileName) // Update program when file changes. @@ -100,7 +103,7 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa configFileParsingDiagnostics: errors, projectReferences, } - if (options.incremental) { + if (incremental) { builderProgram = ts.createIncrementalProgram(programOptions) program = builderProgram.getProgram() } else { @@ -114,13 +117,13 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa output: [string, string] = ['', ''] // Must set memory cache before attempting to read file. updateMemoryCache(code, normalizedFileName) - const sourceFile = options.incremental + const sourceFile = incremental ? builderProgram.getSourceFile(normalizedFileName) : program.getSourceFile(normalizedFileName) if (!sourceFile) throw new TypeError(`Unable to read file: ${fileName}`) - const result: _ts.EmitResult = options.incremental + const result: _ts.EmitResult = incremental ? builderProgram.emit( sourceFile, (path, file, _writeByteOrderMark) => { @@ -142,7 +145,7 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa if (configs.shouldReportDiagnostic(normalizedFileName)) { logger.debug( { normalizedFileName }, - `getOutput(): computing diagnostics for ${options.incremental ? 'incremental program' : 'program'}`, + `getOutput(): computing diagnostics for ${incremental ? 'incremental program' : 'program'}`, ) const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile).slice() // will raise or just warn diagnostics depending on config @@ -165,7 +168,7 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa }), ) } - if (configs.tsJest.emit && options.incremental) { + if (configs.tsJest.emit && incremental) { process.on('exit', () => { // Emits `.tsbuildinfo` to filesystem. // @ts-ignore diff --git a/src/compiler/transpile-module.spec.ts b/src/compiler/transpile-module.spec.ts index 5c1ed108b6..dbaaf33e92 100644 --- a/src/compiler/transpile-module.spec.ts +++ b/src/compiler/transpile-module.spec.ts @@ -54,6 +54,25 @@ describe('transpile module with isolatedModule: true', () => { removeSync(fileName) }) + it('should compile tsx file for jsx preserve', () => { + const fileName = `foo.tsx`, + compiler = makeCompiler({ + tsJestConfig: { ...baseTsJestConfig, tsConfig: 'src/__mocks__/tsconfig.json' }, + }), + source = ` + const App = () => { + return <>Test + } + ` + + writeFileSync(fileName, source, 'utf8') + const compiled = compiler.compile(source, fileName) + + expect(new ProcessedSource(compiled, fileName)).toMatchSnapshot() + + removeSync(fileName) + }) + it('should have correct source maps', () => { const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, tsConfig: false } }), source = 'const f = (v: number) => v\nconst t: number = f(5)' diff --git a/src/config/__snapshots__/config-set.spec.ts.snap b/src/config/__snapshots__/config-set.spec.ts.snap index bb58b30cc6..fb75af528a 100644 --- a/src/config/__snapshots__/config-set.spec.ts.snap +++ b/src/config/__snapshots__/config-set.spec.ts.snap @@ -53,6 +53,7 @@ Object { "throws": true, }, "emit": false, + "incremental": true, "isolatedModules": false, "packageJson": Object { "kind": "file", @@ -143,6 +144,7 @@ Object { "throws": true, }, "emit": false, + "incremental": true, "isolatedModules": false, "packageJson": Object { "kind": "file", diff --git a/src/config/config-set.spec.ts b/src/config/config-set.spec.ts index 3683f768c3..d2641e6095 100644 --- a/src/config/config-set.spec.ts +++ b/src/config/config-set.spec.ts @@ -966,7 +966,7 @@ describe('cacheKey', () => { cs.jsonValue.value = val // digest is mocked in src/__mocks__/index.ts expect(cs.cacheKey).toMatchInlineSnapshot( - `"{\\"digest\\":\\"a0d51ca854194df8191d0e65c0ca4730f510f332\\",\\"jest\\":{\\"__backported\\":true,\\"globals\\":{}},\\"projectDepVersions\\":{\\"dev\\":\\"1.2.5\\",\\"opt\\":\\"1.2.3\\",\\"peer\\":\\"1.2.4\\",\\"std\\":\\"1.2.6\\"},\\"transformers\\":[\\"hoisting-jest-mock@1\\"],\\"tsJest\\":{\\"compiler\\":\\"typescript\\",\\"compilerHost\\":false,\\"diagnostics\\":{\\"ignoreCodes\\":[6059,18002,18003],\\"pretty\\":true,\\"throws\\":true},\\"emit\\":false,\\"isolatedModules\\":false,\\"packageJson\\":{\\"kind\\":\\"file\\"},\\"transformers\\":[]},\\"tsconfig\\":{\\"declaration\\":false,\\"inlineSourceMap\\":false,\\"inlineSources\\":true,\\"module\\":1,\\"noEmit\\":false,\\"removeComments\\":false,\\"sourceMap\\":true,\\"target\\":1}}"`, + `"{\\"digest\\":\\"a0d51ca854194df8191d0e65c0ca4730f510f332\\",\\"jest\\":{\\"__backported\\":true,\\"globals\\":{}},\\"projectDepVersions\\":{\\"dev\\":\\"1.2.5\\",\\"opt\\":\\"1.2.3\\",\\"peer\\":\\"1.2.4\\",\\"std\\":\\"1.2.6\\"},\\"transformers\\":[\\"hoisting-jest-mock@1\\"],\\"tsJest\\":{\\"compiler\\":\\"typescript\\",\\"compilerHost\\":false,\\"diagnostics\\":{\\"ignoreCodes\\":[6059,18002,18003],\\"pretty\\":true,\\"throws\\":true},\\"emit\\":false,\\"incremental\\":true,\\"isolatedModules\\":false,\\"packageJson\\":{\\"kind\\":\\"file\\"},\\"transformers\\":[]},\\"tsconfig\\":{\\"declaration\\":false,\\"inlineSourceMap\\":false,\\"inlineSources\\":true,\\"module\\":1,\\"noEmit\\":false,\\"removeComments\\":false,\\"sourceMap\\":true,\\"target\\":1}}"`, ) }) }) // cacheKey diff --git a/src/config/config-set.ts b/src/config/config-set.ts index c39d5bea61..de04735210 100644 --- a/src/config/config-set.ts +++ b/src/config/config-set.ts @@ -266,6 +266,7 @@ export class ConfigSet { const res: TsJestConfig = { tsConfig, compilerHost: options.compilerHost ?? false, + incremental: options.incremental ?? true, emit: options.emit ?? false, packageJson, babelConfig, diff --git a/src/ts-jest-transformer.spec.ts b/src/ts-jest-transformer.spec.ts index c0cc3e4209..1e9aef0f06 100644 --- a/src/ts-jest-transformer.spec.ts +++ b/src/ts-jest-transformer.spec.ts @@ -8,7 +8,15 @@ import { ConfigSet } from './config/config-set' import { TsJestTransformer } from './ts-jest-transformer' describe('configFor', () => { - it('should return the same config-set for same values', () => { + it('should return the same config-set for same values with jest config string is not in configSetsIndex', () => { + const obj1 = { cwd: '/foo/.', rootDir: '/bar//dummy/..', globals: {} } + const str = stringify(obj1) + const cs3 = new TsJestTransformer().configsFor(str) + expect(cs3.cwd).toBe(`${sep}foo`) + expect(cs3.rootDir).toBe(`${sep}bar`) + }) + + it('should return the same config-set for same values with jest config string in configSetsIndex', () => { const obj1 = { cwd: '/foo/.', rootDir: '/bar//dummy/..', globals: {} } const obj2 = { ...obj1 } const str = stringify(obj1) @@ -70,12 +78,12 @@ describe('process', () => { it('should process ts input without babel', () => { expect(process()).toBe(`ts:${INPUT}`) expect(config.shouldStringifyContent.mock.calls).toMatchInlineSnapshot(` -Array [ - Array [ - "/foo/bar.ts", - ], -] -`) + Array [ + Array [ + "/foo/bar.ts", + ], + ] + `) expect(config.tsCompiler.compile.mock.calls).toMatchInlineSnapshot(` Array [ Array [ @@ -194,6 +202,11 @@ Array [ `) }) + it('should return empty string when trying to process definition file types', () => { + args[1] = '/foo/bar.d.ts' + expect(process()).toBe('') + }) + it('should warn when trying to process unknown file types', () => { args[1] = '/foo/bar.jest' const logs = logTargetMock() diff --git a/src/ts-jest-transformer.ts b/src/ts-jest-transformer.ts index 17b5658ae0..69796476fd 100644 --- a/src/ts-jest-transformer.ts +++ b/src/ts-jest-transformer.ts @@ -62,7 +62,7 @@ export class TsJestTransformer implements Transformer { return `[object TsJestTransformer<#${this.id}>]` } - configsFor(jestConfig: Config.ProjectConfig | string) { + configsFor(jestConfig: Config.ProjectConfig | string): ConfigSet { let csi: ConfigSetIndexItem | undefined let jestConfigObj: Config.ProjectConfig if (typeof jestConfig === 'string') { diff --git a/src/types.ts b/src/types.ts index 1b5b8e75f2..831130d3ef 100644 --- a/src/types.ts +++ b/src/types.ts @@ -44,6 +44,13 @@ export interface TsJestGlobalOptions { */ compilerHost?: boolean + /** + * Use TypeScript's Incremental Program. This option only works when `compilerHost` is `true` + * TODO: Remove this flag when we can make project references working with our Incremental Program + * @default false + */ + incremental?: boolean + /** * Emit compiled files into `.ts-jest` directory * @@ -142,6 +149,7 @@ export interface TsJestConfig { packageJson: TsJestConfig$packageJson isolatedModules: boolean compilerHost: boolean + incremental: boolean // TODO: Remove this flag when we can make project references working with our Incremental Program emit: boolean compiler: string diagnostics: TsJestConfig$diagnostics