From a89bdf3523994daad1760d155e79e4781c15302c Mon Sep 17 00:00:00 2001 From: Ahn Date: Tue, 31 Mar 2020 22:03:02 +0200 Subject: [PATCH 1/3] fix(compiler): do type checking while compiling file --- .../allow-js/{ => with-outDir}/bar.spec.ts | 0 .../allow-js/{ => with-outDir}/bar.ts | 0 .../allow-js/{ => with-outDir}/esm.spec.js | 0 .../allow-js/{ => with-outDir}/foo.js | 0 .../allow-js/{ => with-outDir}/foo.spec.js | 0 .../allow-js/{ => with-outDir}/tsconfig.json | 0 .../allow-js/without-outDir/bar.spec.ts | 10 ++ e2e/__cases__/allow-js/without-outDir/bar.ts | 1 + .../allow-js/without-outDir/esm.spec.js | 5 + e2e/__cases__/allow-js/without-outDir/foo.js | 1 + .../allow-js/without-outDir/foo.spec.js | 10 ++ .../allow-js/without-outDir/tsconfig.json | 6 + e2e/__cases__/diagnostics/main.spec.ts | 16 ++- e2e/__cases__/diagnostics/main.ts | 5 +- .../__snapshots__/allow-js.test.ts.snap | 40 +++--- .../__snapshots__/compiler-host.test.ts.snap | 24 ++++ .../__snapshots__/diagnostics.test.ts.snap | 120 +++++++++++++++--- .../__snapshots__/logger.test.ts.snap | 48 +++---- e2e/__tests__/diagnostics.test.ts | 38 +++++- package-lock.json | 69 +++++++--- package.json | 4 +- src/__helpers__/fakers.ts | 1 + src/compiler/compiler-utils.ts | 52 ++++++++ src/compiler/instance.ts | 14 +- src/compiler/language-service.spec.ts | 8 +- src/compiler/language-service.ts | 27 +++- src/compiler/program.spec.ts | 58 ++++----- src/compiler/program.ts | 56 ++++---- src/config/config-set.spec.ts | 4 - src/config/config-set.ts | 12 +- src/ts-jest-transformer.spec.ts | 65 +--------- src/ts-jest-transformer.ts | 3 - src/types.ts | 5 +- 33 files changed, 468 insertions(+), 234 deletions(-) rename e2e/__cases__/allow-js/{ => with-outDir}/bar.spec.ts (100%) rename e2e/__cases__/allow-js/{ => with-outDir}/bar.ts (100%) rename e2e/__cases__/allow-js/{ => with-outDir}/esm.spec.js (100%) rename e2e/__cases__/allow-js/{ => with-outDir}/foo.js (100%) rename e2e/__cases__/allow-js/{ => with-outDir}/foo.spec.js (100%) rename e2e/__cases__/allow-js/{ => with-outDir}/tsconfig.json (100%) create mode 100644 e2e/__cases__/allow-js/without-outDir/bar.spec.ts create mode 100644 e2e/__cases__/allow-js/without-outDir/bar.ts create mode 100644 e2e/__cases__/allow-js/without-outDir/esm.spec.js create mode 100644 e2e/__cases__/allow-js/without-outDir/foo.js create mode 100644 e2e/__cases__/allow-js/without-outDir/foo.spec.js create mode 100644 e2e/__cases__/allow-js/without-outDir/tsconfig.json create mode 100644 src/compiler/compiler-utils.ts diff --git a/e2e/__cases__/allow-js/bar.spec.ts b/e2e/__cases__/allow-js/with-outDir/bar.spec.ts similarity index 100% rename from e2e/__cases__/allow-js/bar.spec.ts rename to e2e/__cases__/allow-js/with-outDir/bar.spec.ts diff --git a/e2e/__cases__/allow-js/bar.ts b/e2e/__cases__/allow-js/with-outDir/bar.ts similarity index 100% rename from e2e/__cases__/allow-js/bar.ts rename to e2e/__cases__/allow-js/with-outDir/bar.ts diff --git a/e2e/__cases__/allow-js/esm.spec.js b/e2e/__cases__/allow-js/with-outDir/esm.spec.js similarity index 100% rename from e2e/__cases__/allow-js/esm.spec.js rename to e2e/__cases__/allow-js/with-outDir/esm.spec.js diff --git a/e2e/__cases__/allow-js/foo.js b/e2e/__cases__/allow-js/with-outDir/foo.js similarity index 100% rename from e2e/__cases__/allow-js/foo.js rename to e2e/__cases__/allow-js/with-outDir/foo.js diff --git a/e2e/__cases__/allow-js/foo.spec.js b/e2e/__cases__/allow-js/with-outDir/foo.spec.js similarity index 100% rename from e2e/__cases__/allow-js/foo.spec.js rename to e2e/__cases__/allow-js/with-outDir/foo.spec.js diff --git a/e2e/__cases__/allow-js/tsconfig.json b/e2e/__cases__/allow-js/with-outDir/tsconfig.json similarity index 100% rename from e2e/__cases__/allow-js/tsconfig.json rename to e2e/__cases__/allow-js/with-outDir/tsconfig.json diff --git a/e2e/__cases__/allow-js/without-outDir/bar.spec.ts b/e2e/__cases__/allow-js/without-outDir/bar.spec.ts new file mode 100644 index 0000000000..b2be7ec5e8 --- /dev/null +++ b/e2e/__cases__/allow-js/without-outDir/bar.spec.ts @@ -0,0 +1,10 @@ +import * as foo from './foo' +import bar = require('./bar') + +test('foo', () => { + expect(foo).toBe('FOO!') +}) + +test('bar', () => { + expect(bar).toBe('BAR!') +}) diff --git a/e2e/__cases__/allow-js/without-outDir/bar.ts b/e2e/__cases__/allow-js/without-outDir/bar.ts new file mode 100644 index 0000000000..03df82b30b --- /dev/null +++ b/e2e/__cases__/allow-js/without-outDir/bar.ts @@ -0,0 +1 @@ +export = 'BAR!' diff --git a/e2e/__cases__/allow-js/without-outDir/esm.spec.js b/e2e/__cases__/allow-js/without-outDir/esm.spec.js new file mode 100644 index 0000000000..4672def549 --- /dev/null +++ b/e2e/__cases__/allow-js/without-outDir/esm.spec.js @@ -0,0 +1,5 @@ +import * as bar from './bar' + +test('esm', () => { + expect(bar).toBe('BAR!') +}) diff --git a/e2e/__cases__/allow-js/without-outDir/foo.js b/e2e/__cases__/allow-js/without-outDir/foo.js new file mode 100644 index 0000000000..73cfb2112e --- /dev/null +++ b/e2e/__cases__/allow-js/without-outDir/foo.js @@ -0,0 +1 @@ +module.exports = 'FOO!' diff --git a/e2e/__cases__/allow-js/without-outDir/foo.spec.js b/e2e/__cases__/allow-js/without-outDir/foo.spec.js new file mode 100644 index 0000000000..d6eb95ee1a --- /dev/null +++ b/e2e/__cases__/allow-js/without-outDir/foo.spec.js @@ -0,0 +1,10 @@ +const foo = require('./foo') +const bar = require('./bar') + +test('foo', () => { + expect(foo).toBe('FOO!') +}) + +test('bar', () => { + expect(bar).toBe('BAR!') +}) diff --git a/e2e/__cases__/allow-js/without-outDir/tsconfig.json b/e2e/__cases__/allow-js/without-outDir/tsconfig.json new file mode 100644 index 0000000000..26f31aa261 --- /dev/null +++ b/e2e/__cases__/allow-js/without-outDir/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "target": "es5", + "allowJs": true + } +} diff --git a/e2e/__cases__/diagnostics/main.spec.ts b/e2e/__cases__/diagnostics/main.spec.ts index 4a6c38bbcd..e161a242b4 100644 --- a/e2e/__cases__/diagnostics/main.spec.ts +++ b/e2e/__cases__/diagnostics/main.spec.ts @@ -1,5 +1,13 @@ -import { strInNumOut } from './main' +import { Thing } from "./main"; -it('should pass', () => { - expect(strInNumOut('1')).toBe('1') -}) +// See the Thing definition. Changing the type definition should result in a compile failure here. +export const thing: Thing = { a: 1 }; +function doTheThing() { + return 1 + 2; +} + +describe("Thing", () => { + it("should do the thing", () => { + expect(doTheThing()).toEqual(3); + }); +}); diff --git a/e2e/__cases__/diagnostics/main.ts b/e2e/__cases__/diagnostics/main.ts index 56484de330..4746c79aec 100644 --- a/e2e/__cases__/diagnostics/main.ts +++ b/e2e/__cases__/diagnostics/main.ts @@ -1,3 +1,4 @@ -export function strInNumOut(input: string): number { - return input +export type Thing = { + a: number; + // b: number; } diff --git a/e2e/__tests__/__snapshots__/allow-js.test.ts.snap b/e2e/__tests__/__snapshots__/allow-js.test.ts.snap index 400e658f16..45f7eb50b0 100644 --- a/e2e/__tests__/__snapshots__/allow-js.test.ts.snap +++ b/e2e/__tests__/__snapshots__/allow-js.test.ts.snap @@ -6,11 +6,13 @@ exports[`using babel-jest for js files should pass using template "default" 1`] ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - PASS ./bar.spec.ts - PASS ./foo.spec.js + PASS without-outDir/bar.spec.ts + PASS with-outDir/bar.spec.ts + PASS with-outDir/foo.spec.js + PASS without-outDir/foo.spec.js - Test Suites: 2 passed, 2 total - Tests: 4 passed, 4 total + Test Suites: 4 passed, 4 total + Tests: 8 passed, 8 total Snapshots: 0 total Time: XXs Ran all test suites. @@ -23,11 +25,13 @@ exports[`using babel-jest for js files should pass using template "with-babel-7" ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - PASS ./bar.spec.ts - PASS ./foo.spec.js + PASS without-outDir/bar.spec.ts + PASS with-outDir/bar.spec.ts + PASS with-outDir/foo.spec.js + PASS without-outDir/foo.spec.js - Test Suites: 2 passed, 2 total - Tests: 4 passed, 4 total + Test Suites: 4 passed, 4 total + Tests: 8 passed, 8 total Snapshots: 0 total Time: XXs Ran all test suites. @@ -40,11 +44,13 @@ exports[`using babel-jest for js files should pass using template "with-babel-7- ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - PASS ./bar.spec.ts - PASS ./foo.spec.js + PASS without-outDir/bar.spec.ts + PASS with-outDir/bar.spec.ts + PASS without-outDir/foo.spec.js + PASS with-outDir/foo.spec.js - Test Suites: 2 passed, 2 total - Tests: 4 passed, 4 total + Test Suites: 4 passed, 4 total + Tests: 8 passed, 8 total Snapshots: 0 total Time: XXs Ran all test suites. @@ -57,11 +63,13 @@ exports[`using babel-jest for js files should pass using template "with-typescri ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - PASS ./bar.spec.ts - PASS ./foo.spec.js + PASS without-outDir/bar.spec.ts + PASS with-outDir/bar.spec.ts + PASS without-outDir/foo.spec.js + PASS with-outDir/foo.spec.js - Test Suites: 2 passed, 2 total - Tests: 4 passed, 4 total + Test Suites: 4 passed, 4 total + Tests: 8 passed, 8 total Snapshots: 0 total Time: XXs Ran all test suites. diff --git a/e2e/__tests__/__snapshots__/compiler-host.test.ts.snap b/e2e/__tests__/__snapshots__/compiler-host.test.ts.snap index 1f5899ccb8..8708126c3d 100644 --- a/e2e/__tests__/__snapshots__/compiler-host.test.ts.snap +++ b/e2e/__tests__/__snapshots__/compiler-host.test.ts.snap @@ -51,6 +51,10 @@ exports[`With compilerHost enabled and incremental disabled should pass using te ===[ STDERR ]=================================================================== ts-jest[ts-compiler] (WARN) main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + 4 const x: string = g(5) + ~ + ts-jest[ts-compiler] (WARN) 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 @@ -72,6 +76,10 @@ exports[`With compilerHost enabled and incremental disabled should pass using te ===[ STDERR ]=================================================================== ts-jest[ts-compiler] (WARN) main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + 4 const x: string = g(5) + ~ + ts-jest[ts-compiler] (WARN) 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 @@ -93,6 +101,10 @@ exports[`With compilerHost enabled and incremental disabled should pass using te ===[ STDERR ]=================================================================== ts-jest[ts-compiler] (WARN) main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + 4 const x: string = g(5) + ~ + ts-jest[ts-compiler] (WARN) 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 @@ -157,6 +169,10 @@ exports[`With compilerHost enabled and incremental enabled should pass using tem ===[ STDERR ]=================================================================== ts-jest[ts-compiler] (WARN) main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + 4 const x: string = g(5) + ~ + ts-jest[ts-compiler] (WARN) 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 @@ -178,6 +194,10 @@ exports[`With compilerHost enabled and incremental enabled should pass using tem ===[ STDERR ]=================================================================== ts-jest[ts-compiler] (WARN) main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + 4 const x: string = g(5) + ~ + ts-jest[ts-compiler] (WARN) 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 @@ -199,6 +219,10 @@ exports[`With compilerHost enabled and incremental enabled should pass using tem ===[ STDERR ]=================================================================== ts-jest[ts-compiler] (WARN) main.spec.ts:4:9 - error TS2322: Type 'number' is not assignable to type 'string'. + 4 const x: string = g(5) + ~ + ts-jest[ts-compiler] (WARN) 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 diff --git a/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap b/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap index 1d81a46716..adf0a9a012 100644 --- a/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap +++ b/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap @@ -1,6 +1,78 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`With diagnostics, first throws should fail using template "default" 1`] = ` +exports[`With diagnostics, should reevaluate with cached content first successful should pass using template "default" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./main.spec.ts + Thing + √ should do the thing + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With diagnostics, should reevaluate with cached content first successful should pass using template "with-babel-7" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./main.spec.ts + Thing + √ should do the thing + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With diagnostics, should reevaluate with cached content first successful should pass using template "with-babel-7-string-config" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./main.spec.ts + Thing + √ should do the thing + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With diagnostics, should reevaluate with cached content first successful should pass using template "with-typescript-2-7" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./main.spec.ts + Thing + √ should do the thing + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With diagnostics, should reevaluate with cached content then throw when content has changed should fail using template "default" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -9,10 +81,15 @@ exports[`With diagnostics, first throws should fail using template "default" 1`] FAIL ./main.spec.ts ● Test suite failed to run - main.ts:2:3 - error TS2322: Type 'string' is not assignable to type 'number'. + main.spec.ts:4:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. - 2 return input - ~~~~~~~~~~~~ + 4 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. Test Suites: 1 failed, 1 total Tests: 0 total @@ -22,7 +99,7 @@ exports[`With diagnostics, first throws should fail using template "default" 1`] ================================================================================ `; -exports[`With diagnostics, first throws should fail using template "with-babel-7" 1`] = ` +exports[`With diagnostics, should reevaluate with cached content then throw when content has changed should fail using template "with-babel-7" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -31,10 +108,15 @@ exports[`With diagnostics, first throws should fail using template "with-babel-7 FAIL ./main.spec.ts ● Test suite failed to run - main.ts:2:3 - error TS2322: Type 'string' is not assignable to type 'number'. + main.spec.ts:4:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 4 export const thing: Thing = { a: 1 }; + ~~~~~ - 2 return input - ~~~~~~~~~~~~ + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. Test Suites: 1 failed, 1 total Tests: 0 total @@ -44,7 +126,7 @@ exports[`With diagnostics, first throws should fail using template "with-babel-7 ================================================================================ `; -exports[`With diagnostics, first throws should fail using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics, should reevaluate with cached content then throw when content has changed should fail using template "with-babel-7-string-config" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -53,10 +135,15 @@ exports[`With diagnostics, first throws should fail using template "with-babel-7 FAIL ./main.spec.ts ● Test suite failed to run - main.ts:2:3 - error TS2322: Type 'string' is not assignable to type 'number'. + main.spec.ts:4:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 4 export const thing: Thing = { a: 1 }; + ~~~~~ - 2 return input - ~~~~~~~~~~~~ + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. Test Suites: 1 failed, 1 total Tests: 0 total @@ -66,7 +153,7 @@ exports[`With diagnostics, first throws should fail using template "with-babel-7 ================================================================================ `; -exports[`With diagnostics, first throws should fail using template "with-typescript-2-7" 1`] = ` +exports[`With diagnostics, should reevaluate with cached content then throw when content has changed should fail using template "with-typescript-2-7" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -75,10 +162,11 @@ exports[`With diagnostics, first throws should fail using template "with-typescr FAIL ./main.spec.ts ● Test suite failed to run - main.ts:2:3 - error TS2322: Type 'string' is not assignable to type 'number'. + main.spec.ts:4:14 - error TS2322: Type '{ a: number; }' is not assignable to type 'Thing'. + Property 'b' is missing in type '{ a: number; }'. - 2 return input - ~~~~~~~~~~~~ + 4 export const thing: Thing = { a: 1 }; + ~~~~~ Test Suites: 1 failed, 1 total Tests: 0 total diff --git a/e2e/__tests__/__snapshots__/logger.test.ts.snap b/e2e/__tests__/__snapshots__/logger.test.ts.snap index 1bc7b07701..89741b94ae 100644 --- a/e2e/__tests__/__snapshots__/logger.test.ts.snap +++ b/e2e/__tests__/__snapshots__/logger.test.ts.snap @@ -12,30 +12,28 @@ Array [ "[level:20] backporting config", "[level:20] normalized jest config", "[level:20] normalized ts-jest config", + "[level:20] babel is disabled", "[level:20] loaded module typescript", "[level:20] patching typescript", "[level:20] checking version of typescript: OK", "[level:20] readTsConfig(): reading /tsconfig.json", "[level:20] normalized typescript config", + "[level:20] processing /Hello.spec.ts", "[level:20] file caching disabled", "[level:20] compileUsingLanguageService(): create typescript compiler", "[level:20] compileUsingLanguageService(): creating language service", - "[level:20] updateMemoryCache(): update memory cache for language service", - "[level:20] compileFn(): computing diagnostics for language service", - "[level:20] babel is disabled", - "[level:20] processing /Hello.spec.ts", "[level:20] readThrough(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", + "[level:20] cacheResolvedModules(): get resolved modules of test file /Hello.spec.ts", "[level:20] computing cache key for /Hello.ts", - "[level:20] updateMemoryCache(): update memory cache for language service", - "[level:20] compileFn(): computing diagnostics for language service", "[level:20] processing /Hello.ts", "[level:20] readThrough(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", + "[level:20] diagnoseFn(): computing diagnostics for test file that imports /Hello.ts using language service", ] `; @@ -51,35 +49,33 @@ Array [ "[level:20] backporting config", "[level:20] normalized jest config", "[level:20] normalized ts-jest config", + "[level:20] normalized babel config via ts-jest option", "[level:20] loaded module typescript", "[level:20] patching typescript", "[level:20] checking version of typescript: OK", "[level:20] readTsConfig(): reading /tsconfig.json", "[level:20] normalized typescript config", - "[level:20] file caching disabled", - "[level:20] compileUsingLanguageService(): create typescript compiler", - "[level:20] compileUsingLanguageService(): creating language service", - "[level:20] updateMemoryCache(): update memory cache for language service", - "[level:20] compileFn(): computing diagnostics for language service", - "[level:20] normalized babel config via ts-jest option", "[level:20] processing /Hello.spec.ts", "[level:20] creating babel-jest transformer", "[level:20] loaded module babel-jest", "[level:20] patching babel-jest", "[level:20] checking version of babel-jest: OK", + "[level:20] file caching disabled", + "[level:20] compileUsingLanguageService(): create typescript compiler", + "[level:20] compileUsingLanguageService(): creating language service", "[level:20] readThrough(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", + "[level:20] cacheResolvedModules(): get resolved modules of test file /Hello.spec.ts", "[level:20] calling babel-jest processor", "[level:20] computing cache key for /Hello.ts", - "[level:20] updateMemoryCache(): update memory cache for language service", - "[level:20] compileFn(): computing diagnostics for language service", "[level:20] processing /Hello.ts", "[level:20] readThrough(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", + "[level:20] diagnoseFn(): computing diagnostics for test file that imports /Hello.ts using language service", "[level:20] calling babel-jest processor", ] `; @@ -97,35 +93,33 @@ Array [ "[level:20] normalized jest config", "[level:20] resolved path from babel.config.js to /babel.config.js", "[level:20] normalized ts-jest config", + "[level:20] normalized babel config via ts-jest option", "[level:20] loaded module typescript", "[level:20] patching typescript", "[level:20] checking version of typescript: OK", "[level:20] readTsConfig(): reading /tsconfig.json", "[level:20] normalized typescript config", - "[level:20] file caching disabled", - "[level:20] compileUsingLanguageService(): create typescript compiler", - "[level:20] compileUsingLanguageService(): creating language service", - "[level:20] updateMemoryCache(): update memory cache for language service", - "[level:20] compileFn(): computing diagnostics for language service", - "[level:20] normalized babel config via ts-jest option", "[level:20] processing /Hello.spec.ts", "[level:20] creating babel-jest transformer", "[level:20] loaded module babel-jest", "[level:20] patching babel-jest", "[level:20] checking version of babel-jest: OK", + "[level:20] file caching disabled", + "[level:20] compileUsingLanguageService(): create typescript compiler", + "[level:20] compileUsingLanguageService(): creating language service", "[level:20] readThrough(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", + "[level:20] cacheResolvedModules(): get resolved modules of test file /Hello.spec.ts", "[level:20] calling babel-jest processor", "[level:20] computing cache key for /Hello.ts", - "[level:20] updateMemoryCache(): update memory cache for language service", - "[level:20] compileFn(): computing diagnostics for language service", "[level:20] processing /Hello.ts", "[level:20] readThrough(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", + "[level:20] diagnoseFn(): computing diagnostics for test file that imports /Hello.ts using language service", "[level:20] calling babel-jest processor", ] `; @@ -142,30 +136,28 @@ Array [ "[level:20] backporting config", "[level:20] normalized jest config", "[level:20] normalized ts-jest config", + "[level:20] babel is disabled", "[level:20] loaded module typescript", "[level:20] patching typescript", "[level:20] checking version of typescript: OK", "[level:20] readTsConfig(): reading /tsconfig.json", "[level:20] normalized typescript config", + "[level:20] processing /Hello.spec.ts", "[level:20] file caching disabled", "[level:20] compileUsingLanguageService(): create typescript compiler", "[level:20] compileUsingLanguageService(): creating language service", - "[level:20] updateMemoryCache(): update memory cache for language service", - "[level:20] compileFn(): computing diagnostics for language service", - "[level:20] babel is disabled", - "[level:20] processing /Hello.spec.ts", "[level:20] readThrough(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", + "[level:20] cacheResolvedModules(): get resolved modules of test file /Hello.spec.ts", "[level:20] computing cache key for /Hello.ts", - "[level:20] updateMemoryCache(): update memory cache for language service", - "[level:20] compileFn(): computing diagnostics for language service", "[level:20] processing /Hello.ts", "[level:20] readThrough(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", + "[level:20] diagnoseFn(): computing diagnostics for test file that imports /Hello.ts using language service", ] `; diff --git a/e2e/__tests__/diagnostics.test.ts b/e2e/__tests__/diagnostics.test.ts index a118b33e6a..f24a9b7067 100644 --- a/e2e/__tests__/diagnostics.test.ts +++ b/e2e/__tests__/diagnostics.test.ts @@ -1,14 +1,40 @@ +import { writeFileSync } from 'fs' +import { join } from 'path' + import { allValidPackageSets } from '../__helpers__/templates' import { configureTestCase } from '../__helpers__/test-case' -describe('With diagnostics, first throws', () => { +describe('With diagnostics, should reevaluate with cached content', () => { const testCase = configureTestCase('diagnostics') - testCase.runWithTemplates(allValidPackageSets, 1, (runTest, { testLabel }) => { - it(testLabel, () => { - const result = runTest() - expect(result.status).toBe(1) - expect(result).toMatchSnapshot() + describe('first successful', () => { + testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(0) + expect(result).toMatchSnapshot() + }) + }) + }) + + describe('then throw when content has changed', () => { + beforeAll(() => { + writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }`) + }) + + afterAll(() => { + writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { + a: number; + // b: number; +}`) + }) + + testCase.runWithTemplates(allValidPackageSets, 1, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(1) + expect(result).toMatchSnapshot() + }) }) }) }) diff --git a/package-lock.json b/package-lock.json index ed111edd2f..ee20ba2299 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1289,6 +1289,12 @@ } } }, + "@types/braces": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.0.tgz", + "integrity": "sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==", + "dev": true + }, "@types/buffer-from": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/buffer-from/-/buffer-from-1.1.0.tgz", @@ -1402,6 +1408,15 @@ "@types/lodash": "*" } }, + "@types/micromatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.1.tgz", + "integrity": "sha512-my6fLBvpY70KattTNzYOK6KU1oR1+UCz9ug/JbcF5UrEmeCt9P7DV2t7L8+t18mMPINqGQCE4O8PLOPbI84gxw==", + "dev": true, + "requires": { + "@types/braces": "*" + } + }, "@types/mkdirp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.0.tgz", @@ -1921,7 +1936,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -3523,7 +3537,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -4586,8 +4599,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-obj": { "version": "1.0.1", @@ -6403,9 +6415,9 @@ "dev": true }, "lint-staged": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.1.0.tgz", - "integrity": "sha512-WzZ/T+O/aEaaT679sMgI4JqK5mnG69V5KQSouzVsShzZ8wGWte39HT3z61LsxjVNeCf8m/ChhvWJa2wTiQLy5A==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.1.1.tgz", + "integrity": "sha512-wAeu/ePaBAOfwM2+cVbgPWDtn17B0Sxiv0NvNEqDAIvB8Yhvl60vafKFiK4grcYn87K1iK+a0zVoETvKbdT9/Q==", "dev": true, "requires": { "chalk": "^3.0.0", @@ -7073,7 +7085,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.0.5" @@ -7595,8 +7606,7 @@ "picomatch": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", - "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", - "dev": true + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==" }, "pidtree": { "version": "0.3.1", @@ -8730,24 +8740,46 @@ "es-abstract": "^1.17.0-next.1" } }, + "string.prototype.trimend": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz", + "integrity": "sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" } }, "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz", + "integrity": "sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, "string_decoder": { @@ -9046,7 +9078,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } diff --git a/package.json b/package.json index 544ab43b68..8be9c64f08 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "json5": "2.x", "lodash.memoize": "4.x", "make-error": "1.x", + "micromatch": "4.x", "mkdirp": "1.x", "resolve": "1.x", "semver": "6.x", @@ -97,9 +98,10 @@ "@types/lodash.memoize": "4.x", "@types/lodash.merge": "4.x", "@types/lodash.set": "4.x", + "@types/micromatch": "4.x", "@types/mkdirp": "latest", "@types/node": "10.x", - "@types/react": "^16.x", + "@types/react": "16.x", "@types/resolve": "latest", "@types/semver": "latest", "@types/yargs": "latest", diff --git a/src/__helpers__/fakers.ts b/src/__helpers__/fakers.ts index d5ec454953..fcac848db3 100644 --- a/src/__helpers__/fakers.ts +++ b/src/__helpers__/fakers.ts @@ -69,6 +69,7 @@ export function makeCompiler({ ...(tsJestConfig.diagnostics as any), pretty: false, } + jestConfig = { ...jestConfig, testMatch: ['^.+\\.tsx?$'], testRegex: ['^.+\\.[tj]sx?$'] } const cs = new ConfigSet(getJestConfig(jestConfig, tsJestConfig), parentConfig) return createCompiler(cs) diff --git a/src/compiler/compiler-utils.ts b/src/compiler/compiler-utils.ts new file mode 100644 index 0000000000..b0f108a065 --- /dev/null +++ b/src/compiler/compiler-utils.ts @@ -0,0 +1,52 @@ +import { Logger } from 'bs-logger' +import { writeFileSync } from 'fs' +import { join, normalize } from 'path' +import * as _ts from 'typescript' + +import { MemoryCache } from '../types' +import { sha1 } from '../util/sha1' + +/** + * @internal + */ +export const hasOwn = Object.prototype.hasOwnProperty +/** + * @internal + */ +export function getResolvedModulesCache(cachedir: string): string { + return join(cachedir, sha1('ts-jest-resolved-modules', '\x00')) +} + +/** + * @internal + * Get resolved modules of a test file and put into memory cache + */ +export function cacheResolvedModules( + fileName: string, + memoryCache: MemoryCache, + program: _ts.Program, + cachedir: string | undefined, + logger: Logger, +) { + // @ts-ignore + const importReferences = program.getSourceFile(fileName)!.imports + /** + * Ugly trick while waiting for https://github.com/microsoft/TypeScript/issues/33994 + */ + if (importReferences.length) { + logger.debug({ fileName }, `cacheResolvedModules(): get resolved modules of test file ${fileName}`) + + memoryCache.resolvedModules[fileName] = importReferences + .filter((importReference: any) => importReference.parent.parent.resolvedModules?.get(importReference.text)) + .map((importReference: any) => { + return normalize( + (importReference.parent.parent.resolvedModules.get(importReference.text) as _ts.ResolvedModule) + .resolvedFileName, + ) + }) + .reduce((a: any, b: any) => a.concat(b), []) + if (cachedir) { + writeFileSync(getResolvedModulesCache(cachedir), JSON.stringify(memoryCache.resolvedModules)) + } + } +} diff --git a/src/compiler/instance.ts b/src/compiler/instance.ts index 20cf839946..472b94cd27 100644 --- a/src/compiler/instance.ts +++ b/src/compiler/instance.ts @@ -38,6 +38,7 @@ import { ConfigSet } from '../config/config-set' import { CompileFn, CompilerInstance, MemoryCache, TsCompiler } from '../types' import { sha1 } from '../util/sha1' +import { getResolvedModulesCache } from './compiler-utils' import { compileUsingLanguageService } from './language-service' import { compileUsingProgram } from './program' import { compileUsingTranspileModule } from './transpile-module' @@ -100,9 +101,11 @@ const readThrough = ( if (!cachedir) { return (code: string, fileName: string, lineOffset?: number) => { const normalizedFileName = normalize(fileName) + logger.debug({ normalizedFileName }, 'readThrough(): no cache') - const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset) - const output = updateOutput(value, fileName, sourceMap, getExtension) + + const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset), + output = updateOutput(value, fileName, sourceMap, getExtension) memoryCache.outputs[normalizedFileName] = output return output @@ -111,6 +114,10 @@ const readThrough = ( // Make sure the cache directory exists before continuing. mkdirp.sync(cachedir) + try { + const resolvedModulesCache = readFileSync(getResolvedModulesCache(cachedir), 'utf-8') + memoryCache.resolvedModules = JSON.parse(resolvedModulesCache) + } catch (e) {} return (code: string, fileName: string, lineOffset?: number) => { const normalizedFileName = normalize(fileName), @@ -158,6 +165,7 @@ export const createCompiler = (configs: ConfigSet): TsCompiler => { contents: Object.create(null), versions: Object.create(null), outputs: Object.create(null), + resolvedModules: Object.create(null), } // Enable `allowJs` when flag is set. if (compilerOptions.allowJs) { @@ -184,5 +192,5 @@ export const createCompiler = (configs: ConfigSet): TsCompiler => { } const compile = readThrough(cachedir, memoryCache, compilerInstance.compileFn, getExtension, logger) - return { cwd: configs.cwd, compile, program: compilerInstance.program, diagnose: compilerInstance.diagnoseFn } + return { cwd: configs.cwd, compile, program: compilerInstance.program } } diff --git a/src/compiler/language-service.spec.ts b/src/compiler/language-service.spec.ts index 34893c0e90..7a652e806f 100644 --- a/src/compiler/language-service.spec.ts +++ b/src/compiler/language-service.spec.ts @@ -36,6 +36,8 @@ describe('language service', () => { "[level:20] updateMemoryCache(): update memory cache for language service ", "[level:20] visitSourceFileNode(): hoisting + ", + "[level:20] diagnoseFn(): computing diagnostics for test file that imports test-cache.ts using language service ", "[level:20] readThrough(): writing caches ", @@ -144,9 +146,8 @@ const x: string = g(5) tsJestConfig: { tsConfig: false, diagnostics: { pathRegex: fileName } }, }) writeFileSync(fileName, source, 'utf8') - compiler.compile(source, fileName) - expect(() => compiler.diagnose!(source, fileName)).toThrowErrorMatchingSnapshot() + expect(() => compiler.compile(source, fileName)).toThrowErrorMatchingSnapshot() removeSync(fileName) }) @@ -161,9 +162,8 @@ const t: string = f(5) tsJestConfig: { tsConfig: false, diagnostics: { pathRegex: 'bar.ts' } }, }) writeFileSync(fileName, source, 'utf8') - compiler.compile(source, fileName) - expect(() => compiler.diagnose!(source, fileName)).not.toThrowError() + expect(() => compiler.compile(source, fileName)).not.toThrowError() removeSync(fileName) }) diff --git a/src/compiler/language-service.ts b/src/compiler/language-service.ts index 25a8082cbb..5da2e85b64 100644 --- a/src/compiler/language-service.ts +++ b/src/compiler/language-service.ts @@ -1,5 +1,6 @@ import { LogContexts, LogLevels, Logger } from 'bs-logger' import memoize = require('lodash.memoize') +import micromatch = require('micromatch') import { basename, normalize, relative } from 'path' import * as _ts from 'typescript' @@ -7,7 +8,16 @@ import { ConfigSet } from '../config/config-set' import { CompilerInstance, MemoryCache, SourceOutput } from '../types' import { Errors, interpolate } from '../util/messages' -const hasOwn = Object.prototype.hasOwnProperty +import { cacheResolvedModules, hasOwn } from './compiler-utils' + +function doTypeChecking(configs: ConfigSet, fileName: string, service: _ts.LanguageService, logger: Logger) { + if (configs.shouldReportDiagnostic(fileName)) { + // Get the relevant diagnostics - this is 3x faster than `getPreEmitDiagnostics`. + const diagnostics = service.getSemanticDiagnostics(fileName).concat(service.getSyntacticDiagnostics(fileName)) + // will raise or just warn diagnostics depending on config + configs.raiseDiagnostics(diagnostics, fileName, logger) + } +} /** * @internal @@ -99,12 +109,25 @@ export const compileUsingLanguageService = ( // Must set memory cache before attempting to read file. updateMemoryCache(code, normalizedFileName) const output: _ts.EmitOutput = service.getEmitOutput(normalizedFileName) + // Do type checking by getting TypeScript diagnostics + doTypeChecking(configs, normalizedFileName, service, logger) + if (micromatch.isMatch(normalizedFileName, configs.testMatchPatterns)) { + cacheResolvedModules(normalizedFileName, memoryCache, service.getProgram()!, configs.tsCacheDir, logger) + } else { + logger.debug( + `diagnoseFn(): computing diagnostics for test file that imports ${normalizedFileName} using language service`, + ) + Object.entries(memoryCache.resolvedModules) + .filter(entry => entry[1].find(modulePath => modulePath === normalizedFileName)) + .forEach(entry => { + doTypeChecking(configs, entry[0], service, logger) + }) + } /* istanbul ignore next (this should never happen but is kept for security) */ if (output.emitSkipped) { throw new TypeError(`${relative(cwd, normalizedFileName)}: Emit skipped for language service`) } - // Throw an error when requiring `.d.ts` files. if (!output.outputFiles.length) { throw new TypeError( diff --git a/src/compiler/program.spec.ts b/src/compiler/program.spec.ts index 183591b132..908ab54117 100644 --- a/src/compiler/program.spec.ts +++ b/src/compiler/program.spec.ts @@ -38,11 +38,7 @@ const t: string = f(5) }, }) - try { - compiler.compile(source, fileName) - } catch (e) {} - - expect(() => compiler.diagnose!(source, fileName)).toThrowErrorMatchingSnapshot() + expect(() => compiler.compile(source, fileName)).toThrowErrorMatchingSnapshot() }) it('should not report diagnostics with pathRegex config matches file name', () => { @@ -56,9 +52,9 @@ const t: string = f(5) try { compiler.compile(source, fileName) - } catch (e) {} - - expect(() => compiler.diagnose!(source, fileName)).not.toThrowError() + } catch (e) { + expect(e).not.toContain('TypeScript diagnostics') + } }) }) @@ -72,11 +68,7 @@ const t: string = f(5) }, }) - try { - compiler.compile(source, fileName) - } catch (e) {} - - expect(() => compiler.diagnose!(source, fileName)).toThrowErrorMatchingSnapshot() + expect(() => compiler.compile(source, fileName)).toThrowErrorMatchingSnapshot() }) it('should not report diagnostics with pathRegex config does not match file name', () => { @@ -90,9 +82,9 @@ const t: string = f(5) try { compiler.compile(source, fileName) - } catch (e) {} - - expect(() => compiler.diagnose!(source, fileName)).not.toThrowError() + } catch (e) { + expect(e).not.toContain('TypeScript diagnostics') + } }) }) }) @@ -171,12 +163,14 @@ describe('cache', () => { expect(logTarget.filteredLines(LogLevels.debug, Infinity)).toMatchInlineSnapshot(` Array [ "[level:20] readThrough(): cache miss - ", - "[level:20] compileFn(): compiling using program ", "[level:20] updateMemoryCache(): update memory cache for program + ", + "[level:20] compileFn(): compiling using program ", "[level:20] visitSourceFileNode(): hoisting + ", + "[level:20] diagnoseFn(): computing diagnostics for test file that imports test-cache.ts using program ", "[level:20] readThrough(): writing caches ", @@ -208,19 +202,21 @@ describe('cache', () => { logTarget.clear() const compiled1 = compiler.compile(source, fileName) expect(logTarget.filteredLines(LogLevels.debug, Infinity)).toMatchInlineSnapshot(` -Array [ - "[level:20] readThrough(): cache miss -", - "[level:20] compileFn(): compiling using incremental program -", - "[level:20] updateMemoryCache(): update memory cache for incremental program -", - "[level:20] visitSourceFileNode(): hoisting -", - "[level:20] readThrough(): writing caches -", -] -`) + Array [ + "[level:20] readThrough(): cache miss + ", + "[level:20] updateMemoryCache(): update memory cache for incremental program + ", + "[level:20] compileFn(): compiling using incremental program + ", + "[level:20] visitSourceFileNode(): hoisting + ", + "[level:20] diagnoseFn(): computing diagnostics for test file that imports test-cache.ts using incremental program + ", + "[level:20] readThrough(): writing caches + ", + ] + `) logTarget.clear() const compiled2 = compiler.compile(source, fileName) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 0cef7b999b..9863fa28ac 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1,5 +1,6 @@ import { LogContexts, LogLevels, Logger } from 'bs-logger' import memoize = require('lodash.memoize') +import micromatch = require('micromatch') import { basename, normalize, relative } from 'path' import * as _ts from 'typescript' @@ -7,7 +8,16 @@ import { ConfigSet } from '../config/config-set' import { CompilerInstance, MemoryCache, SourceOutput } from '../types' import { Errors, interpolate } from '../util/messages' -const hasOwn = Object.prototype.hasOwnProperty +import { cacheResolvedModules, hasOwn } from './compiler-utils' + +function doTypeChecking(configs: ConfigSet, fileName: string, program: _ts.Program, logger: Logger) { + if (configs.shouldReportDiagnostic(fileName)) { + const sourceFile = program.getSourceFile(fileName), + diagnostics = program.getSemanticDiagnostics(sourceFile).concat(program.getSyntacticDiagnostics(sourceFile)) + // will raise or just warn diagnostics depending on config + configs.raiseDiagnostics(diagnostics, fileName, logger) + } +} /** * @internal @@ -18,7 +28,8 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa const ts = configs.compilerModule, cwd = configs.cwd, { options, projectReferences, errors } = configs.typescript, - incremental = configs.tsJest.incremental + incremental = configs.tsJest.incremental, + programDebugText = `${incremental ? 'incremental program' : 'program'}` const compilerHostTraceCtx = { namespace: 'ts:compilerHost', call: null, @@ -74,10 +85,7 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa // Read and cache custom transformers. const customTransformers = configs.tsCustomTransformers, updateMemoryCache = (code: string, fileName: string): void => { - logger.debug( - { fileName }, - `updateMemoryCache(): update memory cache for ${incremental ? 'incremental program' : 'program'}`, - ) + logger.debug({ fileName }, `updateMemoryCache(): update memory cache for ${programDebugText}`) const sourceFile = incremental ? builderProgram.getSourceFile(fileName) : program.getSourceFile(fileName) if (!hasOwn.call(memoryCache.versions, fileName)) { @@ -112,11 +120,6 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa compileFn: (code: string, fileName: string): SourceOutput => { const normalizedFileName = normalize(fileName), output: [string, string] = ['', ''] - - logger.debug( - { normalizedFileName }, - `compileFn(): compiling using ${incremental ? 'incremental program' : 'program'}`, - ) // Must set memory cache before attempting to read file. updateMemoryCache(code, normalizedFileName) const sourceFile = incremental @@ -125,6 +128,8 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa if (!sourceFile) throw new TypeError(`Unable to read file: ${fileName}`) + logger.debug({ normalizedFileName }, `compileFn(): compiling using ${programDebugText}`) + const result: _ts.EmitResult = incremental ? builderProgram.emit( sourceFile, @@ -144,7 +149,21 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa undefined, customTransformers, ) + // Do type checking by getting TypeScript diagnostics + doTypeChecking(configs, normalizedFileName, program, logger) + if (micromatch.isMatch(normalizedFileName, configs.testMatchPatterns)) { + cacheResolvedModules(normalizedFileName, memoryCache, program, configs.tsCacheDir, logger) + } else { + logger.debug( + `diagnoseFn(): computing diagnostics for test file that imports ${normalizedFileName} using ${programDebugText}`, + ) + Object.entries(memoryCache.resolvedModules) + .filter(entry => entry[1].find(modulePath => modulePath === normalizedFileName)) + .forEach(entry => { + doTypeChecking(configs, entry[0], program, logger) + }) + } if (result.emitSkipped) { throw new TypeError(`${relative(cwd, fileName)}: Emit skipped`) } @@ -160,21 +179,6 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa return output }, - diagnoseFn: (code: string, filePath: string) => { - const normalizedFileName = normalize(filePath) - updateMemoryCache(code, normalizedFileName) - if (configs.shouldReportDiagnostic(normalizedFileName)) { - logger.debug( - { normalizedFileName }, - `compileFn(): computing diagnostics for ${incremental ? 'incremental program' : 'program'}`, - ) - - const sourceFile = program.getSourceFile(normalizedFileName), - diagnostics = program.getSemanticDiagnostics(sourceFile).concat(program.getSyntacticDiagnostics(sourceFile)) - // will raise or just warn diagnostics depending on config - configs.raiseDiagnostics(diagnostics, normalizedFileName, logger) - } - }, program, } } diff --git a/src/config/config-set.spec.ts b/src/config/config-set.spec.ts index abfe04013c..5f99046a1c 100644 --- a/src/config/config-set.spec.ts +++ b/src/config/config-set.spec.ts @@ -462,10 +462,6 @@ describe('typescript', () => { }) }) - it('should include default outDir $$ts-jest$$ when allowJs is enabled and no outDir from config', () => { - expect(get(void 0, { tsConfig: { allowJs: true } }).options.outDir).toBe('$$ts-jest$$') - }) - it('should be able to read extends', () => { const cs = createConfigSet({ tsJestConfig: { tsConfig: 'tsconfig.build.json' }, diff --git a/src/config/config-set.ts b/src/config/config-set.ts index f0a378fa4d..276bdeb9df 100644 --- a/src/config/config-set.ts +++ b/src/config/config-set.ts @@ -187,6 +187,14 @@ export class ConfigSet { return config } + /** + * @internal + */ + @Memoize() + get testMatchPatterns(): string[] { + return this.jest.testMatch.concat(this.jest.testRegex) + } + /** * @internal */ @@ -770,10 +778,6 @@ export class ConfigSet { finalOptions.allowSyntheticDefaultImports = true } } - // Make sure when allowJs is enabled, outDir is set otherwise we run into error: Cannot write file ... because it would overwrite input - if (finalOptions.allowJs && !finalOptions.outDir) { - finalOptions.outDir = '$$ts-jest$$' - } // ensure undefined are removed and other values are overridden for (const key of Object.keys(forcedOptions)) { diff --git a/src/ts-jest-transformer.spec.ts b/src/ts-jest-transformer.spec.ts index 6165edb061..7c7e52a5a8 100644 --- a/src/ts-jest-transformer.spec.ts +++ b/src/ts-jest-transformer.spec.ts @@ -238,20 +238,11 @@ Array [ }) describe('getCacheKey', () => { - let tr: TsJestTransformer - - beforeEach(() => { - tr = new TsJestTransformer() - }) - it('should be different for each argument value', () => { - jest.spyOn(tr, 'configsFor').mockImplementation( - jestConfigStr => - (({ - cacheKey: jestConfigStr, - tsCompiler: {}, - } as unknown) as ConfigSet), - ) + const tr = new TsJestTransformer() + jest + .spyOn(tr, 'configsFor') + .mockImplementation(jestConfigStr => (({ cacheKey: jestConfigStr } as unknown) as ConfigSet)) const input = { fileContent: 'export default "foo"', fileName: 'foo.ts', @@ -272,52 +263,4 @@ describe('getCacheKey', () => { // unique array should have same length expect(keys.filter((k, i, all) => all.indexOf(k) === i)).toHaveLength(keys.length) }) - - it('should call diagnose() to do type checking for js/jsx/ts/tsx file but not d.ts file', () => { - const tsCompilerStub = { diagnose: jest.fn() }, - baseInput = { - fileContent: 'export default "foo"', - jestConfigStr: '{"foo": "bar"}', - options: { instrument: false, rootDir: '/foo' }, - } - jest.spyOn(tr, 'configsFor').mockImplementation( - jestConfigStr => - (({ - cacheKey: jestConfigStr, - tsCompiler: tsCompilerStub, - } as unknown) as ConfigSet), - ) - const jsInput = { - ...baseInput, - fileName: 'foo.js', - }, - jsxInput = { - ...baseInput, - fileName: 'foo.jsx', - }, - tsInput = { - ...baseInput, - fileName: 'foo.ts', - }, - tsxInput = { - ...baseInput, - fileName: 'foo.tsx', - }, - dtsInput = { - ...baseInput, - fileContent: 'type Foo = (code: string) => void', - fileName: 'foo.d.ts', - } - tr.getCacheKey(jsInput.fileContent, jsInput.fileName, jsInput.jestConfigStr, jsInput.options) - tr.getCacheKey(jsxInput.fileContent, jsxInput.fileName, jsxInput.jestConfigStr, jsxInput.options) - tr.getCacheKey(tsInput.fileContent, tsInput.fileName, tsInput.jestConfigStr, tsInput.options) - tr.getCacheKey(tsxInput.fileContent, tsxInput.fileName, tsxInput.jestConfigStr, tsxInput.options) - tr.getCacheKey(dtsInput.fileContent, dtsInput.fileName, dtsInput.jestConfigStr, dtsInput.options) - - expect(tsCompilerStub.diagnose).toHaveBeenCalledTimes(4) - expect(tsCompilerStub.diagnose).toHaveBeenNthCalledWith(1, jsInput.fileContent, jsInput.fileName) - expect(tsCompilerStub.diagnose).toHaveBeenNthCalledWith(2, jsxInput.fileContent, jsxInput.fileName) - expect(tsCompilerStub.diagnose).toHaveBeenNthCalledWith(3, tsInput.fileContent, tsInput.fileName) - expect(tsCompilerStub.diagnose).toHaveBeenNthCalledWith(4, tsxInput.fileContent, tsxInput.fileName) - }) }) diff --git a/src/ts-jest-transformer.ts b/src/ts-jest-transformer.ts index 641121a21f..e3247ea84b 100644 --- a/src/ts-jest-transformer.ts +++ b/src/ts-jest-transformer.ts @@ -189,9 +189,6 @@ export class TsJestTransformer implements Transformer { const configs = this.configsFor(jestConfigStr) // we do not instrument, ensure it is false all the time const { instrument = false, rootDir = configs.rootDir } = transformOptions - if (configs.tsCompiler.diagnose && (checkJsFile(filePath) || checkTsFile(filePath))) { - configs.tsCompiler.diagnose(fileContent, filePath) - } return sha1( configs.cacheKey, diff --git a/src/types.ts b/src/types.ts index 0f7d144bed..0704fb6f37 100644 --- a/src/types.ts +++ b/src/types.ts @@ -185,10 +185,6 @@ export interface TsCompiler { * @internal */ compile(code: string, fileName: string, lineOffset?: number): string - /** - * @internal - */ - diagnose: DiagnoseFn | undefined program: _ts.Program | undefined } @@ -206,6 +202,7 @@ export interface MemoryCache { contents: { [filePath: string]: string | undefined } versions: { [filePath: string]: number } outputs: { [filePath: string]: string } + resolvedModules: { [testFilePath: string]: string[] } } /** * @internal From 8cf4c6fda7354f9d1953818e7ffe8e299a9c957d Mon Sep 17 00:00:00 2001 From: Ahn Date: Wed, 1 Apr 2020 17:26:02 +0200 Subject: [PATCH 2/3] fix(compiler): do type checking while compiling file --- e2e/__cases__/diagnostics/main.ts | 2 +- e2e/__cases__/isolated-modules/main.ts | 2 +- e2e/__helpers__/templates.ts | 8 +- .../__snapshots__/diagnostics.test.ts.snap | 500 +++++++++++------- .../__snapshots__/logger.test.ts.snap | 4 - e2e/__tests__/allow-js.test.ts | 8 +- e2e/__tests__/diagnostics.test.ts | 177 ++++--- src/compiler/compiler-utils.spec.ts | 50 +- src/compiler/compiler-utils.ts | 6 +- src/compiler/instance.ts | 35 +- src/compiler/language-service.spec.ts | 98 ++-- src/compiler/language-service.ts | 90 ++-- src/compiler/program.spec.ts | 80 +-- src/compiler/program.ts | 166 +++--- src/compiler/transpile-module.spec.ts | 54 +- src/compiler/transpile-module.ts | 14 +- src/ts-jest-transformer.ts | 28 +- tslint.json | 1 - 18 files changed, 719 insertions(+), 604 deletions(-) diff --git a/e2e/__cases__/diagnostics/main.ts b/e2e/__cases__/diagnostics/main.ts index 2e1e99b7b3..a4d045ad90 100644 --- a/e2e/__cases__/diagnostics/main.ts +++ b/e2e/__cases__/diagnostics/main.ts @@ -1 +1 @@ -export type Thing = { a: number, b: number } \ No newline at end of file +export type Thing = { a: number, b: number } diff --git a/e2e/__cases__/isolated-modules/main.ts b/e2e/__cases__/isolated-modules/main.ts index 2e1e99b7b3..a4d045ad90 100644 --- a/e2e/__cases__/isolated-modules/main.ts +++ b/e2e/__cases__/isolated-modules/main.ts @@ -1 +1 @@ -export type Thing = { a: number, b: number } \ No newline at end of file +export type Thing = { a: number, b: number } diff --git a/e2e/__helpers__/templates.ts b/e2e/__helpers__/templates.ts index ff20228f6b..30560cff53 100644 --- a/e2e/__helpers__/templates.ts +++ b/e2e/__helpers__/templates.ts @@ -6,7 +6,7 @@ export enum PackageSets { // invalid unsupportedVersion = 'with-unsupported-version', } -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] +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 allPackageSetsWithProgram = [PackageSets.default, PackageSets.babel7, PackageSets.babel7StringConfig] +export const allPackageSetsWithoutProgram = [PackageSets.typescript2_7, PackageSets.unsupportedVersion] diff --git a/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap b/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap index 951f03ded2..a0953cf8bc 100644 --- a/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap +++ b/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Diagnostics using incremental program with throw first throw should fail using template "default" 1`] = ` +exports[`With diagnostics throw using incremental program first throw should fail using template "default" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -27,7 +27,7 @@ exports[`Diagnostics using incremental program with throw first throw should fai ================================================================================ `; -exports[`Diagnostics using incremental program with throw first throw should fail using template "with-babel-7" 1`] = ` +exports[`With diagnostics throw using incremental program first throw should fail using template "with-babel-7" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -54,7 +54,7 @@ exports[`Diagnostics using incremental program with throw first throw should fai ================================================================================ `; -exports[`Diagnostics using incremental program with throw first throw should fail using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics throw using incremental program first throw should fail using template "with-babel-7-string-config" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -81,7 +81,7 @@ exports[`Diagnostics using incremental program with throw first throw should fai ================================================================================ `; -exports[`Diagnostics using incremental program with throw then passed when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` +exports[`With diagnostics throw using incremental program then passed when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -98,7 +98,7 @@ exports[`Diagnostics using incremental program with throw then passed when conte ================================================================================ `; -exports[`Diagnostics using incremental program with throw then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` +exports[`With diagnostics throw using incremental program then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -115,7 +115,7 @@ exports[`Diagnostics using incremental program with throw then passed when conte ================================================================================ `; -exports[`Diagnostics using incremental program with throw then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics throw using incremental program then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -132,8 +132,8 @@ exports[`Diagnostics using incremental program with throw then passed when conte ================================================================================ `; -exports[`Diagnostics using incremental program with typescript version not supported incremental program should fail using template "with-typescript-2-7" 1`] = ` - × jest --no-cache +exports[`With diagnostics throw using incremental program with unsupported version should fail using template "with-typescript-2-7" 1`] = ` + × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -153,8 +153,8 @@ exports[`Diagnostics using incremental program with typescript version not suppo ================================================================================ `; -exports[`Diagnostics using incremental program with typescript version not supported incremental program should fail using template "with-unsupported-version" 1`] = ` - × jest --no-cache +exports[`With diagnostics throw using incremental program with unsupported version should fail using template "with-unsupported-version" 1`] = ` + × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -175,41 +175,111 @@ exports[`Diagnostics using incremental program with typescript version not suppo ================================================================================ `; -exports[`Diagnostics using incremental program with warn only first passed without warning should pass using template "default" 1`] = ` - √ jest - ↳ exit code: 0 +exports[`With diagnostics throw using language service first throw should fail using template "default" 1`] = ` + × jest + ↳ exit code: 1 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - PASS ./main.spec.ts - √ should do the thing + FAIL ./main.spec.ts + ● Test suite failed to run - Test Suites: 1 passed, 1 total - Tests: 1 passed, 1 total + main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. + + Test Suites: 1 failed, 1 total + Tests: 0 total Snapshots: 0 total Time: XXs Ran all test suites. ================================================================================ `; -exports[`Diagnostics using incremental program with warn only first passed without warning should pass using template "with-babel-7" 1`] = ` - √ jest - ↳ exit code: 0 +exports[`With diagnostics throw using language service first throw should fail using template "with-babel-7" 1`] = ` + × jest + ↳ exit code: 1 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - PASS ./main.spec.ts - √ should do the thing + FAIL ./main.spec.ts + ● Test suite failed to run - Test Suites: 1 passed, 1 total - Tests: 1 passed, 1 total + main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. + + Test Suites: 1 failed, 1 total + Tests: 0 total Snapshots: 0 total Time: XXs Ran all test suites. ================================================================================ `; -exports[`Diagnostics using incremental program with warn only first passed without warning should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics throw using language service first throw should fail using template "with-babel-7-string-config" 1`] = ` + × jest + ↳ exit code: 1 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + FAIL ./main.spec.ts + ● Test suite failed to run + + main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. + + Test Suites: 1 failed, 1 total + Tests: 0 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With diagnostics throw using language service first throw should fail using template "with-typescript-2-7" 1`] = ` + × jest + ↳ exit code: 1 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + FAIL ./main.spec.ts + ● Test suite failed to run + + main.spec.ts:3:14 - error TS2322: Type '{ a: number; }' is not assignable to type 'Thing'. + Property 'b' is missing in type '{ a: number; }'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + Test Suites: 1 failed, 1 total + Tests: 0 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With diagnostics throw using language service then passed when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -226,21 +296,12 @@ exports[`Diagnostics using incremental program with warn only first passed witho ================================================================================ `; -exports[`Diagnostics using incremental program with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "default" 1`] = ` +exports[`With diagnostics throw using language service then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. - - 3 export const thing: Thing = { a: 1 }; - ~~~~~ - - main.ts:1:34 - 1 export type Thing = { a: number, b: number } - ~ - 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -252,21 +313,12 @@ exports[`Diagnostics using incremental program with warn only then show warning ================================================================================ `; -exports[`Diagnostics using incremental program with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "with-babel-7" 1`] = ` +exports[`With diagnostics throw using language service then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. - - 3 export const thing: Thing = { a: 1 }; - ~~~~~ - - main.ts:1:34 - 1 export type Thing = { a: number, b: number } - ~ - 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -278,21 +330,12 @@ exports[`Diagnostics using incremental program with warn only then show warning ================================================================================ `; -exports[`Diagnostics using incremental program with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics throw using language service then passed when content has changed to valid base on cache of the previous run should pass using template "with-typescript-2-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. - - 3 export const thing: Thing = { a: 1 }; - ~~~~~ - - main.ts:1:34 - 1 export type Thing = { a: number, b: number } - ~ - 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -304,7 +347,7 @@ exports[`Diagnostics using incremental program with warn only then show warning ================================================================================ `; -exports[`Diagnostics using language service with throw first throw should fail using template "default" 1`] = ` +exports[`With diagnostics throw using program first throw should fail using template "default" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -331,7 +374,7 @@ exports[`Diagnostics using language service with throw first throw should fail u ================================================================================ `; -exports[`Diagnostics using language service with throw first throw should fail using template "with-babel-7" 1`] = ` +exports[`With diagnostics throw using program first throw should fail using template "with-babel-7" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -358,7 +401,7 @@ exports[`Diagnostics using language service with throw first throw should fail u ================================================================================ `; -exports[`Diagnostics using language service with throw first throw should fail using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics throw using program first throw should fail using template "with-babel-7-string-config" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -385,30 +428,7 @@ exports[`Diagnostics using language service with throw first throw should fail u ================================================================================ `; -exports[`Diagnostics using language service with throw first throw should fail using template "with-typescript-2-7" 1`] = ` - × jest - ↳ exit code: 1 - ===[ STDOUT ]=================================================================== - - ===[ STDERR ]=================================================================== - FAIL ./main.spec.ts - ● Test suite failed to run - - main.spec.ts:3:14 - error TS2322: Type '{ a: number; }' is not assignable to type 'Thing'. - Property 'b' is missing in type '{ a: number; }'. - - 3 export const thing: Thing = { a: 1 }; - ~~~~~ - - Test Suites: 1 failed, 1 total - Tests: 0 total - Snapshots: 0 total - Time: XXs - Ran all test suites. - ================================================================================ -`; - -exports[`Diagnostics using language service with throw then passed when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` +exports[`With diagnostics throw using program then passed when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -425,7 +445,7 @@ exports[`Diagnostics using language service with throw then passed when content ================================================================================ `; -exports[`Diagnostics using language service with throw then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` +exports[`With diagnostics throw using program then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -442,7 +462,7 @@ exports[`Diagnostics using language service with throw then passed when content ================================================================================ `; -exports[`Diagnostics using language service with throw then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics throw using program then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -459,63 +479,64 @@ exports[`Diagnostics using language service with throw then passed when content ================================================================================ `; -exports[`Diagnostics using language service with throw then passed when content has changed to valid base on cache of the previous run should pass using template "with-typescript-2-7" 1`] = ` - √ jest - ↳ exit code: 0 +exports[`With diagnostics throw using program with unsupported version should fail using template "with-typescript-2-7" 1`] = ` + × jest + ↳ exit code: 1 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - PASS ./main.spec.ts - √ should do the thing + FAIL ./main.spec.ts + ● Test suite failed to run - Test Suites: 1 passed, 1 total - Tests: 1 passed, 1 total - Snapshots: 0 total - Time: XXs - Ran all test suites. - ================================================================================ -`; - -exports[`Diagnostics using language service with warn only first passed without warning should pass using template "default" 1`] = ` - √ jest - ↳ exit code: 0 - ===[ STDOUT ]=================================================================== + TypeError: Cannot read property 'maxNodeModuleJsDepth' of undefined - ===[ STDERR ]=================================================================== - PASS ./main.spec.ts - √ should do the thing + at Object.createProgram (../../__templates__/with-typescript-2-7/node_modules/typescript/lib/typescript.js:73929:51) - Test Suites: 1 passed, 1 total - Tests: 1 passed, 1 total + Test Suites: 1 failed, 1 total + Tests: 0 total Snapshots: 0 total Time: XXs Ran all test suites. ================================================================================ `; -exports[`Diagnostics using language service with warn only first passed without warning should pass using template "with-babel-7" 1`] = ` - √ jest - ↳ exit code: 0 +exports[`With diagnostics throw using program with unsupported version should fail using template "with-unsupported-version" 1`] = ` + × jest + ↳ exit code: 1 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - PASS ./main.spec.ts - √ should do the thing + 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 - Test Suites: 1 passed, 1 total - Tests: 1 passed, 1 total + 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[`Diagnostics using language service with warn only first passed without warning should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics warn only using incremental program first show warning should pass using template "default" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -527,12 +548,21 @@ exports[`Diagnostics using language service with warn only first passed without ================================================================================ `; -exports[`Diagnostics using language service with warn only first passed without warning should pass using template "with-typescript-2-7" 1`] = ` +exports[`With diagnostics warn only using incremental program first show warning should pass using template "with-babel-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -544,12 +574,21 @@ exports[`Diagnostics using language service with warn only first passed without ================================================================================ `; -exports[`Diagnostics using language service with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "default" 1`] = ` +exports[`With diagnostics warn only using incremental program first show warning should pass using template "with-babel-7-string-config" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -561,7 +600,7 @@ exports[`Diagnostics using language service with warn only then show warning whe ================================================================================ `; -exports[`Diagnostics using language service with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "with-babel-7" 1`] = ` +exports[`With diagnostics warn only using incremental program then not showing warning when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -578,7 +617,7 @@ exports[`Diagnostics using language service with warn only then show warning whe ================================================================================ `; -exports[`Diagnostics using language service with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics warn only using incremental program then not showing warning when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -595,7 +634,7 @@ exports[`Diagnostics using language service with warn only then show warning whe ================================================================================ `; -exports[`Diagnostics using language service with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "with-typescript-2-7" 1`] = ` +exports[`With diagnostics warn only using incremental program then not showing warning when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -612,7 +651,7 @@ exports[`Diagnostics using language service with warn only then show warning whe ================================================================================ `; -exports[`Diagnostics using program with throw first throw should fail using template "default" 1`] = ` +exports[`With diagnostics warn only using incremental program with unsupported version should fail using template "with-typescript-2-7" 1`] = ` × jest ↳ exit code: 1 ===[ STDOUT ]=================================================================== @@ -621,15 +660,9 @@ exports[`Diagnostics using program with throw first throw should fail using temp FAIL ./main.spec.ts ● Test suite failed to run - main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. - - 3 export const thing: Thing = { a: 1 }; - ~~~~~ + TypeError: ts.createIncrementalCompilerHost is not a function - main.ts:1:34 - 1 export type Thing = { a: number, b: number } - ~ - 'b' is declared here. + at Object.exports.compileUsingProgram (../../__templates__/with-typescript-2-7/node_modules/ts-jest/dist/compiler/program.js:40:19) Test Suites: 1 failed, 1 total Tests: 0 total @@ -639,24 +672,19 @@ exports[`Diagnostics using program with throw first throw should fail using temp ================================================================================ `; -exports[`Diagnostics using program with throw first throw should fail using template "with-babel-7" 1`] = ` +exports[`With diagnostics warn only using incremental program with unsupported version should fail using template "with-unsupported-version" 1`] = ` × jest ↳ 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 - main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. - - 3 export const thing: Thing = { a: 1 }; - ~~~~~ + TypeError: ts.createIncrementalCompilerHost is not a function - main.ts:1:34 - 1 export type Thing = { a: number, b: number } - ~ - 'b' is declared here. + at Object.exports.compileUsingProgram (../../__templates__/with-unsupported-version/node_modules/ts-jest/dist/compiler/program.js:40:19) Test Suites: 1 failed, 1 total Tests: 0 total @@ -666,39 +694,47 @@ exports[`Diagnostics using program with throw first throw should fail using temp ================================================================================ `; -exports[`Diagnostics using program with throw first throw should fail using template "with-babel-7-string-config" 1`] = ` - × jest - ↳ exit code: 1 +exports[`With diagnostics warn only using language service first show warning should pass using template "default" 1`] = ` + √ jest + ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - FAIL ./main.spec.ts - ● Test suite failed to run - - main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. - 3 export const thing: Thing = { a: 1 }; - ~~~~~ + 3 export const thing: Thing = { a: 1 }; + ~~~~~ - main.ts:1:34 - 1 export type Thing = { a: number, b: number } - ~ - 'b' is declared here. + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. + PASS ./main.spec.ts + √ should do the thing - Test Suites: 1 failed, 1 total - Tests: 0 total + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total Snapshots: 0 total Time: XXs Ran all test suites. ================================================================================ `; -exports[`Diagnostics using program with throw then passed when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` +exports[`With diagnostics warn only using language service first show warning should pass using template "with-babel-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -710,12 +746,21 @@ exports[`Diagnostics using program with throw then passed when content has chang ================================================================================ `; -exports[`Diagnostics using program with throw then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` +exports[`With diagnostics warn only using language service first show warning should pass using template "with-babel-7-string-config" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -727,12 +772,17 @@ exports[`Diagnostics using program with throw then passed when content has chang ================================================================================ `; -exports[`Diagnostics using program with throw then passed when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics warn only using language service first show warning should pass using template "with-typescript-2-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2322: Type '{ a: number; }' is not assignable to type 'Thing'. + Property 'b' is missing in type '{ a: number; }'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ PASS ./main.spec.ts √ should do the thing @@ -744,50 +794,41 @@ exports[`Diagnostics using program with throw then passed when content has chang ================================================================================ `; -exports[`Diagnostics using program with typescript version not supported program should fail using template "with-typescript-2-7" 1`] = ` - × jest - ↳ exit code: 1 +exports[`With diagnostics warn only using language service then not showing warning when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` + √ jest + ↳ exit code: 0 ===[ 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) + PASS ./main.spec.ts + √ should do the thing - Test Suites: 1 failed, 1 total - Tests: 0 total + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total Snapshots: 0 total Time: XXs Ran all test suites. ================================================================================ `; -exports[`Diagnostics using program with typescript version not supported program should fail using template "with-unsupported-version" 1`] = ` - × jest - ↳ exit code: 1 +exports[`With diagnostics warn only using language service then not showing warning when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` + √ jest + ↳ exit code: 0 ===[ 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) + PASS ./main.spec.ts + √ should do the thing - Test Suites: 1 failed, 1 total - Tests: 0 total + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total Snapshots: 0 total Time: XXs Ran all test suites. ================================================================================ `; -exports[`Diagnostics using program with warn only first passed without warning should pass using template "default" 1`] = ` +exports[`With diagnostics warn only using language service then not showing warning when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -804,7 +845,7 @@ exports[`Diagnostics using program with warn only first passed without warning s ================================================================================ `; -exports[`Diagnostics using program with warn only first passed without warning should pass using template "with-babel-7" 1`] = ` +exports[`With diagnostics warn only using language service then not showing warning when content has changed to valid base on cache of the previous run should pass using template "with-typescript-2-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -821,12 +862,21 @@ exports[`Diagnostics using program with warn only first passed without warning s ================================================================================ `; -exports[`Diagnostics using program with warn only first passed without warning should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics warn only using program first show warning should pass using template "default" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== + ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + + 3 export const thing: Thing = { a: 1 }; + ~~~~~ + + main.ts:1:34 + 1 export type Thing = { a: number, b: number } + ~ + 'b' is declared here. PASS ./main.spec.ts √ should do the thing @@ -838,7 +888,7 @@ exports[`Diagnostics using program with warn only first passed without warning s ================================================================================ `; -exports[`Diagnostics using program with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "default" 1`] = ` +exports[`With diagnostics warn only using program first show warning should pass using template "with-babel-7" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -864,7 +914,7 @@ exports[`Diagnostics using program with warn only then show warning when content ================================================================================ `; -exports[`Diagnostics using program with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "with-babel-7" 1`] = ` +exports[`With diagnostics warn only using program first show warning should pass using template "with-babel-7-string-config" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== @@ -890,21 +940,29 @@ exports[`Diagnostics using program with warn only then show warning when content ================================================================================ `; -exports[`Diagnostics using program with warn only then show warning when content changed to invalid base on cached of the previous run should pass using template "with-babel-7-string-config" 1`] = ` +exports[`With diagnostics warn only using program then not show warning when content has changed to valid base on cache of the previous run should pass using template "default" 1`] = ` √ jest ↳ exit code: 0 ===[ STDOUT ]=================================================================== ===[ STDERR ]=================================================================== - ts-jest[ts-compiler] (WARN) main.spec.ts:3:14 - error TS2741: Property 'b' is missing in type '{ a: number; }' but required in type 'Thing'. + PASS ./main.spec.ts + √ should do the thing - 3 export const thing: Thing = { a: 1 }; - ~~~~~ + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With diagnostics warn only using program then not show warning when content has changed to valid base on cache of the previous run should pass using template "with-babel-7" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== - main.ts:1:34 - 1 export type Thing = { a: number, b: number } - ~ - 'b' is declared here. + ===[ STDERR ]=================================================================== PASS ./main.spec.ts √ should do the thing @@ -915,3 +973,63 @@ exports[`Diagnostics using program with warn only then show warning when content Ran all test suites. ================================================================================ `; + +exports[`With diagnostics warn only using program then not show warning when content has changed to valid base on cache of the previous run should pass using template "with-babel-7-string-config" 1`] = ` + √ jest + ↳ exit code: 0 + ===[ STDOUT ]=================================================================== + + ===[ STDERR ]=================================================================== + PASS ./main.spec.ts + √ should do the thing + + Test Suites: 1 passed, 1 total + Tests: 1 passed, 1 total + Snapshots: 0 total + Time: XXs + Ran all test suites. + ================================================================================ +`; + +exports[`With diagnostics warn only using program with unsupported version should fail using template "with-typescript-2-7" 1`] = ` + × jest + ↳ 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 diagnostics warn only using program with unsupported version should fail using template "with-unsupported-version" 1`] = ` + × jest + ↳ 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. + ================================================================================ +`; diff --git a/e2e/__tests__/__snapshots__/logger.test.ts.snap b/e2e/__tests__/__snapshots__/logger.test.ts.snap index e6e2a0d521..9956fddb97 100644 --- a/e2e/__tests__/__snapshots__/logger.test.ts.snap +++ b/e2e/__tests__/__snapshots__/logger.test.ts.snap @@ -27,7 +27,6 @@ Array [ "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", "[level:20] diagnoseFn(): computing diagnostics for /Hello.spec.ts using language service", - "[level:20] cacheResolvedModules(): get resolved modules of test file /Hello.spec.ts", "[level:20] computing cache key for /Hello.ts", "[level:20] processing /Hello.ts", "[level:20] readThrough(): no cache", @@ -69,7 +68,6 @@ Array [ "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", "[level:20] diagnoseFn(): computing diagnostics for /Hello.spec.ts using language service", - "[level:20] cacheResolvedModules(): get resolved modules of test file /Hello.spec.ts", "[level:20] calling babel-jest processor", "[level:20] computing cache key for /Hello.ts", "[level:20] processing /Hello.ts", @@ -114,7 +112,6 @@ Array [ "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", "[level:20] diagnoseFn(): computing diagnostics for /Hello.spec.ts using language service", - "[level:20] cacheResolvedModules(): get resolved modules of test file /Hello.spec.ts", "[level:20] calling babel-jest processor", "[level:20] computing cache key for /Hello.ts", "[level:20] processing /Hello.ts", @@ -154,7 +151,6 @@ Array [ "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", "[level:20] diagnoseFn(): computing diagnostics for /Hello.spec.ts using language service", - "[level:20] cacheResolvedModules(): get resolved modules of test file /Hello.spec.ts", "[level:20] computing cache key for /Hello.ts", "[level:20] processing /Hello.ts", "[level:20] readThrough(): no cache", diff --git a/e2e/__tests__/allow-js.test.ts b/e2e/__tests__/allow-js.test.ts index 0607ca308d..069aa58552 100644 --- a/e2e/__tests__/allow-js.test.ts +++ b/e2e/__tests__/allow-js.test.ts @@ -2,11 +2,11 @@ import { allPackageSetsWithPreset, allValidPackageSets } from '../__helpers__/te import { configureTestCase } from '../__helpers__/test-case' describe('using babel-jest for js files', () => { - const outDirTestCase = configureTestCase('allow-js', { + const testCase = configureTestCase('allow-js', { jestConfig: { testMatch: null, testRegex: '(foo|bar)\\.spec\\.[jt]s$' }, }) - outDirTestCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { + testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { it(testLabel, () => { const result = runTest() expect(result.status).toBe(0) @@ -16,7 +16,7 @@ describe('using babel-jest for js files', () => { }) describe('using ts-jest for js files', () => { - const outDirTestCase = configureTestCase('allow-js', { + const testCase = configureTestCase('allow-js', { jestConfig: { preset: 'ts-jest/presets/js-with-ts', testMatch: null, @@ -24,7 +24,7 @@ describe('using ts-jest for js files', () => { }, }) - outDirTestCase.runWithTemplates(allPackageSetsWithPreset, 0, (runTest, { testLabel }) => { + testCase.runWithTemplates(allPackageSetsWithPreset, 0, (runTest, { testLabel }) => { it(testLabel, () => { const result = runTest() expect(result.status).toBe(0) diff --git a/e2e/__tests__/diagnostics.test.ts b/e2e/__tests__/diagnostics.test.ts index 6fd75f517c..5d88887fc4 100644 --- a/e2e/__tests__/diagnostics.test.ts +++ b/e2e/__tests__/diagnostics.test.ts @@ -4,8 +4,8 @@ import { join } from 'path' import { allPackageSetsWithProgram, allPackageSetsWithoutProgram, allValidPackageSets } from '../__helpers__/templates' import { configureTestCase } from '../__helpers__/test-case' -describe('Diagnostics using language service', () => { - describe('with throw', () => { +describe('With diagnostics throw', () => { + describe('using language service', () => { const testCase = configureTestCase('diagnostics') describe('first throw', () => { @@ -27,7 +27,7 @@ describe('Diagnostics using language service', () => { }) afterAll(() => { - writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }`) + writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }\n`) }) testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { @@ -40,12 +40,25 @@ describe('Diagnostics using language service', () => { }) }) - describe('with warn only', () => { + describe('using program', () => { const testCase = configureTestCase('diagnostics', { - tsJestConfig: { diagnostics: { warnOnly: true } }, + tsJestConfig: { + compilerHost: true, + incremental: false, + }, }) - describe('first passed without warning', () => { + describe('first throw', () => { + testCase.runWithTemplates(allPackageSetsWithProgram, 1, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(1) + expect(result).toMatchSnapshot() + }) + }) + }) + + describe('then passed when content has changed to valid base on cache of the previous run', () => { beforeAll(() => { writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number; @@ -54,10 +67,10 @@ describe('Diagnostics using language service', () => { }) afterAll(() => { - writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }`) + writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }\n`) }) - testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { + testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { it(testLabel, () => { const result = runTest() expect(result.status).toBe(0) @@ -66,22 +79,23 @@ describe('Diagnostics using language service', () => { }) }) - describe('then show warning when content changed to invalid base on cached of the previous run', () => { - testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { + describe('with unsupported version', () => { + testCase.runWithTemplates(allPackageSetsWithoutProgram, 1, (runTest, { testLabel }) => { it(testLabel, () => { const result = runTest() - expect(result.status).toBe(0) + expect(result.status).toBe(1) expect(result).toMatchSnapshot() }) }) }) }) -}) -describe('Diagnostics using program', () => { - describe('with throw', () => { + describe('using incremental program', () => { const testCase = configureTestCase('diagnostics', { - tsJestConfig: { compilerHost: true, incremental: false }, + tsJestConfig: { + compilerHost: true, + incremental: true, + }, }) describe('first throw', () => { @@ -103,7 +117,7 @@ describe('Diagnostics using program', () => { }) afterAll(() => { - writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }`) + writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }\n`) }) testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { @@ -114,14 +128,38 @@ describe('Diagnostics using program', () => { }) }) }) + + describe('with unsupported version', () => { + testCase.runWithTemplates(allPackageSetsWithoutProgram, 1, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(1) + expect(result).toMatchSnapshot() + }) + }) + }) }) +}) - describe('with warn only', () => { +describe('With diagnostics warn only', () => { + describe('using language service', () => { const testCase = configureTestCase('diagnostics', { - tsJestConfig: { compilerHost: true, incremental: false, diagnostics: { warnOnly: true } }, + tsJestConfig: { + diagnostics: { warnOnly: true }, + }, + }) + + describe('first show warning', () => { + testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(0) + expect(result).toMatchSnapshot() + }) + }) }) - describe('first passed without warning', () => { + describe('then not showing warning when content has changed to valid base on cache of the previous run', () => { beforeAll(() => { writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number; @@ -130,20 +168,10 @@ describe('Diagnostics using program', () => { }) afterAll(() => { - writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }`) + writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }\n`) }) - testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { - it(testLabel, () => { - const result = runTest() - expect(result.status).toBe(0) - expect(result).toMatchSnapshot() - }) - }) - }) - - describe('then show warning when content changed to invalid base on cached of the previous run', () => { - testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { + testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => { it(testLabel, () => { const result = runTest() expect(result.status).toBe(0) @@ -153,38 +181,26 @@ describe('Diagnostics using program', () => { }) }) - describe('with typescript version not supported program', () => { + describe('using program', () => { const testCase = configureTestCase('diagnostics', { - tsJestConfig: { compilerHost: true, incremental: false, diagnostics: { warnOnly: true } }, + tsJestConfig: { + compilerHost: true, + incremental: false, + diagnostics: { warnOnly: true }, + }, }) - testCase.runWithTemplates(allPackageSetsWithoutProgram, 1, (runTest, { testLabel }) => { - it(testLabel, () => { - const result = runTest() - expect(result.status).toBe(1) - expect(result).toMatchSnapshot() - }) - }) - }) -}) - -describe('Diagnostics using incremental program', () => { - describe('with throw', () => { - const testCase = configureTestCase('diagnostics', { - tsJestConfig: { compilerHost: true, incremental: true }, - }) - - describe('first throw', () => { - testCase.runWithTemplates(allPackageSetsWithProgram, 1, (runTest, { testLabel }) => { + describe('first show warning', () => { + testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { it(testLabel, () => { const result = runTest() - expect(result.status).toBe(1) + expect(result.status).toBe(0) expect(result).toMatchSnapshot() }) }) }) - describe('then passed when content has changed to valid base on cache of the previous run', () => { + describe('then not show warning when content has changed to valid base on cache of the previous run', () => { beforeAll(() => { writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number; @@ -193,7 +209,7 @@ describe('Diagnostics using incremental program', () => { }) afterAll(() => { - writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }`) + writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }\n`) }) testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { @@ -204,14 +220,38 @@ describe('Diagnostics using incremental program', () => { }) }) }) + + describe('with unsupported version', () => { + testCase.runWithTemplates(allPackageSetsWithoutProgram, 1, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(1) + expect(result).toMatchSnapshot() + }) + }) + }) }) - describe('with warn only', () => { + describe('using incremental program', () => { const testCase = configureTestCase('diagnostics', { - tsJestConfig: { compilerHost: true, incremental: true, diagnostics: { warnOnly: true } }, + tsJestConfig: { + compilerHost: true, + incremental: true, + diagnostics: { warnOnly: true }, + }, + }) + + describe('first show warning', () => { + testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { + it(testLabel, () => { + const result = runTest() + expect(result.status).toBe(0) + expect(result).toMatchSnapshot() + }) + }) }) - describe('first passed without warning', () => { + describe('then not showing warning when content has changed to valid base on cache of the previous run', () => { beforeAll(() => { writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number; @@ -220,7 +260,7 @@ describe('Diagnostics using incremental program', () => { }) afterAll(() => { - writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }`) + writeFileSync(join(__dirname, '../__cases__/diagnostics/main.ts'), `export type Thing = { a: number, b: number }\n`) }) testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { @@ -232,29 +272,14 @@ describe('Diagnostics using incremental program', () => { }) }) - describe('then show warning when content changed to invalid base on cached of the previous run', () => { - testCase.runWithTemplates(allPackageSetsWithProgram, 0, (runTest, { testLabel }) => { + describe('with unsupported version', () => { + testCase.runWithTemplates(allPackageSetsWithoutProgram, 1, (runTest, { testLabel }) => { it(testLabel, () => { const result = runTest() - expect(result.status).toBe(0) + expect(result.status).toBe(1) expect(result).toMatchSnapshot() }) }) }) }) - - describe('with typescript version not supported incremental program', () => { - const testCase = configureTestCase('diagnostics', { - tsJestConfig: { compilerHost: true, incremental: true, diagnostics: { warnOnly: true } }, - noCache: true, - }) - - testCase.runWithTemplates(allPackageSetsWithoutProgram, 1, (runTest, { testLabel }) => { - it(testLabel, () => { - const result = runTest() - expect(result.status).toBe(1) - expect(result).toMatchSnapshot() - }) - }) - }) }) diff --git a/src/compiler/compiler-utils.spec.ts b/src/compiler/compiler-utils.spec.ts index e7e3d2c963..7066393a30 100644 --- a/src/compiler/compiler-utils.spec.ts +++ b/src/compiler/compiler-utils.spec.ts @@ -36,14 +36,14 @@ describe('cacheResolvedModules', () => { spy.mockRestore() }) - it('should store resolved modules in memory cache and file system when there are resolved modules and cache dir', () => { - const tmp = tempDir('compiler'), - compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { tsConfig: false }, - }), - fileName = 'src/__mocks__/main.spec.ts', - source = JSON.stringify(require('../__mocks__/main.spec')) + it('should store resolved modules in memory cache and file system when there are resolved modules', () => { + const tmp = tempDir('compiler') + const compiler = makeCompiler({ + jestConfig: { cache: true, cacheDirectory: tmp }, + tsJestConfig: { tsConfig: false }, + }) + const fileName = 'src/__mocks__/main.spec.ts' + const source = JSON.stringify(require('../__mocks__/main.spec')) compiler.compile(source, fileName) @@ -55,38 +55,20 @@ describe('cacheResolvedModules', () => { }) it(`should store resolved modules in memory cache but not file system when there aren't resolved modules`, () => { - const tmp = tempDir('compiler'), - compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { tsConfig: false }, - }), - fileName = 'src/__mocks__/thing.spec.ts', - source = JSON.stringify(require('../__mocks__/thing.spec')) + const tmp = tempDir('compiler') + const compiler = makeCompiler({ + jestConfig: { cache: true, cacheDirectory: tmp }, + tsJestConfig: { tsConfig: false }, + }) + const fileName = 'src/__mocks__/thing.spec.ts' + const source = JSON.stringify(require('../__mocks__/thing.spec')) compiler.compile(source, fileName) logTarget.clear() - cacheResolvedModules(fileName, memoryCache, compiler.program!, undefined, logger) + cacheResolvedModules(fileName, memoryCache, compiler.program!, tmp, logger) expect(memoryCache.resolvedModules[fileName]).toBe(undefined) expect(spy).not.toHaveBeenCalled() }) - - it(`should store resolved modules in memory cache but not file system when there are resolved modules but no cache dir`, () => { - const tmp = tempDir('compiler'), - compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { tsConfig: false }, - }), - fileName = 'src/__mocks__/main.spec.ts', - source = JSON.stringify(require('../__mocks__/main.spec')) - - compiler.compile(source, fileName) - - logTarget.clear() - cacheResolvedModules(fileName, memoryCache, compiler.program!, undefined, logger) - - expect(memoryCache.resolvedModules[fileName]).toContain(resolve('src/__mocks__/main.ts')) - expect(spy).not.toHaveBeenCalled() - }) }) diff --git a/src/compiler/compiler-utils.ts b/src/compiler/compiler-utils.ts index b0f108a065..7bb3b19195 100644 --- a/src/compiler/compiler-utils.ts +++ b/src/compiler/compiler-utils.ts @@ -25,7 +25,7 @@ export function cacheResolvedModules( fileName: string, memoryCache: MemoryCache, program: _ts.Program, - cachedir: string | undefined, + cacheDir: string, logger: Logger, ) { // @ts-ignore @@ -45,8 +45,6 @@ export function cacheResolvedModules( ) }) .reduce((a: any, b: any) => a.concat(b), []) - if (cachedir) { - writeFileSync(getResolvedModulesCache(cachedir), JSON.stringify(memoryCache.resolvedModules)) - } + writeFileSync(getResolvedModulesCache(cacheDir), JSON.stringify(memoryCache.resolvedModules)) } } diff --git a/src/compiler/instance.ts b/src/compiler/instance.ts index 472b94cd27..b991e97fb2 100644 --- a/src/compiler/instance.ts +++ b/src/compiler/instance.ts @@ -104,8 +104,8 @@ const readThrough = ( logger.debug({ normalizedFileName }, 'readThrough(): no cache') - const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset), - output = updateOutput(value, fileName, sourceMap, getExtension) + const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset) + const output = updateOutput(value, fileName, sourceMap, getExtension) memoryCache.outputs[normalizedFileName] = output return output @@ -116,14 +116,15 @@ const readThrough = ( mkdirp.sync(cachedir) try { const resolvedModulesCache = readFileSync(getResolvedModulesCache(cachedir), 'utf-8') + /* istanbul ignore next (covered by e2e) */ memoryCache.resolvedModules = JSON.parse(resolvedModulesCache) } catch (e) {} return (code: string, fileName: string, lineOffset?: number) => { - const normalizedFileName = normalize(fileName), - cachePath = join(cachedir, getCacheName(code, normalizedFileName)), - extension = getExtension(normalizedFileName), - outputPath = `${cachePath}${extension}` + const normalizedFileName = normalize(fileName) + const cachePath = join(cachedir, getCacheName(code, normalizedFileName)) + const extension = getExtension(normalizedFileName) + const outputPath = `${cachePath}${extension}` try { const output = readFileSync(outputPath, 'utf8') if (isValidCacheContent(output)) { @@ -136,8 +137,8 @@ const readThrough = ( logger.debug({ fileName }, 'readThrough(): cache miss') - const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset), - output = updateOutput(value, normalizedFileName, sourceMap, getExtension) + const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset) + const output = updateOutput(value, normalizedFileName, sourceMap, getExtension) logger.debug({ normalizedFileName, outputPath }, 'readThrough(): writing caches') @@ -158,15 +159,15 @@ export const createCompiler = (configs: ConfigSet): TsCompiler => { typescript: { options: compilerOptions, fileNames }, tsJest, } = configs - const cachedir = configs.tsCacheDir, - ts = configs.compilerModule, // Require the TypeScript compiler and configuration. - extensions = ['.ts', '.tsx'], - memoryCache: MemoryCache = { - contents: Object.create(null), - versions: Object.create(null), - outputs: Object.create(null), - resolvedModules: Object.create(null), - } + const cachedir = configs.tsCacheDir + const ts = configs.compilerModule // Require the TypeScript compiler and configuration. + const extensions = ['.ts', '.tsx'] + const memoryCache: MemoryCache = { + contents: Object.create(null), + versions: Object.create(null), + outputs: Object.create(null), + resolvedModules: Object.create(null), + } // Enable `allowJs` when flag is set. if (compilerOptions.allowJs) { extensions.push('.js') diff --git a/src/compiler/language-service.spec.ts b/src/compiler/language-service.spec.ts index 88b88414b3..7fba8ab490 100644 --- a/src/compiler/language-service.spec.ts +++ b/src/compiler/language-service.spec.ts @@ -14,13 +14,13 @@ describe('language service', () => { }) it('should use the cache', () => { - const tmp = tempDir('compiler'), - compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { tsConfig: false }, - }), - source = 'console.log("hello")', - fileName = 'test-cache.ts' + const tmp = tempDir('compiler') + const compiler = makeCompiler({ + jestConfig: { cache: true, cacheDirectory: tmp }, + tsJestConfig: { tsConfig: false }, + }) + const source = 'console.log("hello")' + const fileName = 'test-cache.ts' writeFileSync(fileName, source, 'utf8') @@ -61,11 +61,11 @@ describe('language service', () => { }) it('should compile js file for allowJs true', () => { - const fileName = `test-allow-js.js`, - compiler = makeCompiler({ - tsJestConfig: { tsConfig: { allowJs: true, outDir: '$$ts-jest$$' } }, - }), - source = 'export default 42' + const fileName = `test-allow-js.js` + const compiler = makeCompiler({ + tsJestConfig: { tsConfig: { allowJs: true, outDir: '$$ts-jest$$' } }, + }) + const source = 'export default 42' writeFileSync(fileName, source, 'utf8') const compiled = compiler.compile(source, fileName) @@ -76,15 +76,15 @@ describe('language service', () => { }) it('should compile tsx file for jsx preserve', () => { - const fileName = 'test-jsx-preserve.tsx', - compiler = makeCompiler({ - tsJestConfig: { - tsConfig: { - jsx: 'preserve' as any, - }, + const fileName = 'test-jsx-preserve.tsx' + const compiler = makeCompiler({ + tsJestConfig: { + tsConfig: { + jsx: 'preserve' as any, }, - }), - source = ` + }, + }) + const source = ` const App = () => { return <>Test } @@ -98,15 +98,15 @@ describe('language service', () => { }) it('should compile tsx file for other jsx options', () => { - const fileName = 'test-jsx-options.tsx', - compiler = makeCompiler({ - tsJestConfig: { - tsConfig: { - jsx: 'react' as any, - }, + const fileName = 'test-jsx-options.tsx' + const compiler = makeCompiler({ + tsJestConfig: { + tsConfig: { + jsx: 'react' as any, }, - }), - source = ` + }, + }) + const source = ` const App = () => { return <>Test } @@ -120,9 +120,9 @@ describe('language service', () => { }) it('should have correct source maps', () => { - const compiler = makeCompiler({ tsJestConfig: { tsConfig: false } }), - source = 'const gsm = (v: number) => v\nconst h: number = gsm(5)', - fileName = 'test-source-map.ts' + const compiler = makeCompiler({ tsJestConfig: { tsConfig: false } }) + const source = 'const gsm = (v: number) => v\nconst h: number = gsm(5)' + const fileName = 'test-source-map.ts' writeFileSync(fileName, source, 'utf8') const compiled = compiler.compile(source, fileName) @@ -137,14 +137,14 @@ describe('language service', () => { }) it('should report diagnostics related to typings with pathRegex config matches file name', () => { - const fileName = 'test-match-regex-diagnostics.ts', - source = ` + const fileName = 'test-match-regex-diagnostics.ts' + const source = ` const g = (v: number) => v const x: string = g(5) -`, - compiler = makeCompiler({ - tsJestConfig: { tsConfig: false, diagnostics: { pathRegex: fileName } }, - }) +` + const compiler = makeCompiler({ + tsJestConfig: { tsConfig: false, diagnostics: { pathRegex: fileName } }, + }) writeFileSync(fileName, source, 'utf8') expect(() => compiler.compile(source, fileName)).toThrowErrorMatchingSnapshot() @@ -153,14 +153,14 @@ const x: string = g(5) }) it('should not report diagnostics related to typings with pathRegex config does not match file name', () => { - const fileName = 'test-non-match-regex-diagnostics.ts', - source = ` + const fileName = 'test-non-match-regex-diagnostics.ts' + const source = ` const f = (v: number) => v const t: string = f(5) -`, - compiler = makeCompiler({ - tsJestConfig: { tsConfig: false, diagnostics: { pathRegex: 'bar.ts' } }, - }) +` + const compiler = makeCompiler({ + tsJestConfig: { tsConfig: false, diagnostics: { pathRegex: 'bar.ts' } }, + }) writeFileSync(fileName, source, 'utf8') expect(() => compiler.compile(source, fileName)).not.toThrowError() @@ -169,15 +169,15 @@ const t: string = f(5) }) it('should throw error when cannot compile', () => { - const fileName = 'test-cannot-compile.d.ts', - source = ` + const fileName = 'test-cannot-compile.d.ts' + const source = ` interface Foo { a: string } - `, - compiler = makeCompiler({ - tsJestConfig: { tsConfig: false }, - }) + ` + const compiler = makeCompiler({ + tsJestConfig: { tsConfig: false }, + }) writeFileSync(fileName, source, 'utf8') expect(() => compiler.compile(source, fileName)).toThrowErrorMatchingSnapshot() diff --git a/src/compiler/language-service.ts b/src/compiler/language-service.ts index fddd7cdd65..ed18aef5b7 100644 --- a/src/compiler/language-service.ts +++ b/src/compiler/language-service.ts @@ -29,21 +29,22 @@ export const compileUsingLanguageService = ( ): CompilerInstance => { logger.debug('compileUsingLanguageService(): create typescript compiler') - const ts = configs.compilerModule, - cwd = configs.cwd, - { options } = configs.typescript, - serviceHostTraceCtx = { - namespace: 'ts:serviceHost', - call: null, - [LogContexts.logLevel]: LogLevels.trace, - } + const ts = configs.compilerModule + const cwd = configs.cwd + const cacheDir = configs.tsCacheDir + const { options } = configs.typescript + const serviceHostTraceCtx = { + namespace: 'ts:serviceHost', + call: null, + [LogContexts.logLevel]: LogLevels.trace, + } let projectVersion = 1 // Set the file contents into cache. const updateMemoryCache = (code: string, fileName: string) => { logger.debug({ fileName }, `updateMemoryCache(): update memory cache for language service`) - const fileVersion = memoryCache.versions[fileName] ?? 0, - isFileInCache = fileVersion !== 0 + const fileVersion = memoryCache.versions[fileName] ?? 0 + const isFileInCache = fileVersion !== 0 if (!isFileInCache) { memoryCache.versions[fileName] = 1 } @@ -58,8 +59,8 @@ export const compileUsingLanguageService = ( getProjectVersion: () => String(projectVersion), getScriptFileNames: () => Object.keys(memoryCache.versions), getScriptVersion: (fileName: string) => { - const normalizedFileName = normalize(fileName), - version = memoryCache.versions[normalizedFileName] + const normalizedFileName = normalize(fileName) + const version = memoryCache.versions[normalizedFileName] // We need to return `undefined` and not a string here because TypeScript will use // `getScriptVersion` and compare against their own version - which can be `undefined`. @@ -69,19 +70,16 @@ export const compileUsingLanguageService = ( return version === undefined ? ((undefined as any) as string) : String(version) }, getScriptSnapshot(fileName: string) { - const normalizedFileName = normalize(fileName), - hit = hasOwn.call(memoryCache.contents, normalizedFileName) + const normalizedFileName = normalize(fileName) + const hit = hasOwn.call(memoryCache.contents, normalizedFileName) logger.trace({ normalizedFileName, cacheHit: hit }, `getScriptSnapshot():`, 'cache', hit ? 'hit' : 'miss') // Read contents from TypeScript memory cache. - if (!hit) { - memoryCache.contents[normalizedFileName] = ts.sys.readFile(normalizedFileName) - } + if (!hit) memoryCache.contents[normalizedFileName] = ts.sys.readFile(normalizedFileName) const contents = memoryCache.contents[normalizedFileName] - if (contents === undefined) { - return - } + + if (contents === undefined) return return ts.ScriptSnapshot.fromString(contents) }, @@ -113,31 +111,35 @@ export const compileUsingLanguageService = ( logger.debug(`diagnoseFn(): computing diagnostics for ${normalizedFileName} using language service`) doTypeChecking(configs, normalizedFileName, service, logger) + /** + * We don't need the following logic with no cache run because no cache always gives correct typing + */ /* istanbul ignore next (covered by e2e) */ - if (micromatch.isMatch(normalizedFileName, configs.testMatchPatterns)) { - cacheResolvedModules(normalizedFileName, memoryCache, service.getProgram()!, configs.tsCacheDir, logger) - } else { - /* istanbul ignore next (covered by e2e) */ - Object.entries(memoryCache.resolvedModules) - .filter(entry => { - /** - * When imported modules change, we only need to check whether the test file is compiled previously or not. - * Due to jest cache, our memory cache won't contain compiled result of test file so we are sure that we - * can do type checking on test file. By checking memory cache, we can avoid repeatedly doing type checking - * against test file for 1st time run after clearing cache. - */ - return ( - entry[1].find(modulePath => modulePath === normalizedFileName) && - !hasOwn.call(memoryCache.outputs, entry[0]) - ) - }) - .forEach(entry => { - logger.debug( - `diagnoseFn(): computing diagnostics for test file that imports ${normalizedFileName} using language service`, - ) - - doTypeChecking(configs, entry[0], service, logger) - }) + if (cacheDir) { + if (micromatch.isMatch(normalizedFileName, configs.testMatchPatterns)) { + cacheResolvedModules(normalizedFileName, memoryCache, service.getProgram()!, cacheDir, logger) + } else { + /* istanbul ignore next (covered by e2e) */ + Object.entries(memoryCache.resolvedModules) + .filter(entry => { + /** + * When imported modules change, we only need to check whether the test file is compiled previously or not + * base on memory cache. By checking memory cache, we can avoid repeatedly doing type checking against + * test file for 1st time run after clearing cache because + */ + return ( + entry[1].find(modulePath => modulePath === normalizedFileName) && + !hasOwn.call(memoryCache.outputs, entry[0]) + ) + }) + .forEach(entry => { + logger.debug( + `diagnoseFn(): computing diagnostics for test file that imports ${normalizedFileName} using language service`, + ) + + doTypeChecking(configs, entry[0], service, logger) + }) + } } /* istanbul ignore next (this should never happen but is kept for security) */ if (output.emitSkipped) { diff --git a/src/compiler/program.spec.ts b/src/compiler/program.spec.ts index d1031066f7..8761bbbd47 100644 --- a/src/compiler/program.spec.ts +++ b/src/compiler/program.spec.ts @@ -14,8 +14,8 @@ const baseTsJestConfig = { } describe('cache', () => { - const fileName = 'test-cache.ts', - source = 'console.log("hello")' + const fileName = 'test-cache.ts' + const source = 'console.log("hello")' beforeAll(() => { writeFileSync(fileName, source, 'utf8') @@ -26,14 +26,14 @@ describe('cache', () => { }) it('should use the cache with normal program', () => { - const tmp = tempDir('program-compiler'), - compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { - ...baseTsJestConfig, - incremental: false, - }, - }) + const tmp = tempDir('program-compiler') + const compiler = makeCompiler({ + jestConfig: { cache: true, cacheDirectory: tmp }, + tsJestConfig: { + ...baseTsJestConfig, + incremental: false, + }, + }) logTarget.clear() const compiled1 = compiler.compile(source, fileName) @@ -67,14 +67,14 @@ describe('cache', () => { }) 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, - }, - }) + const tmp = tempDir('incremental-program-compiler') + const compiler = makeCompiler({ + jestConfig: { cache: true, cacheDirectory: tmp }, + tsJestConfig: { + ...baseTsJestConfig, + incremental: true, + }, + }) logTarget.clear() const compiled1 = compiler.compile(source, fileName) @@ -109,9 +109,9 @@ describe('cache', () => { }) describe('allowJs', () => { - const fileName = 'test-allowJs.test.js', - source = 'export default 42', - tsConfig = { allowJs: true, outDir: '$$ts-jest$$' } + const fileName = 'test-allowJs.test.js' + const source = 'export default 42' + const tsConfig = { allowJs: true, outDir: '$$ts-jest$$' } beforeAll(() => { writeFileSync(fileName, source, 'utf8') @@ -143,15 +143,15 @@ describe('allowJs', () => { }) describe('jsx preserve', () => { - const fileName = 'test-jsx-preserve.tsx', - source = ` + const fileName = 'test-jsx-preserve.tsx' + const source = ` const App = () => { return <>Test } - `, - tsConfig = { - jsx: 'preserve' as any, - } + ` + const tsConfig = { + jsx: 'preserve' as any, + } beforeAll(() => { writeFileSync(fileName, source, 'utf8') @@ -183,15 +183,15 @@ describe('jsx preserve', () => { }) describe('other jsx options', () => { - const fileName = 'test-jsx-options.tsx', - source = ` + const fileName = 'test-jsx-options.tsx' + const source = ` const App = () => { return <>Test } - `, - tsConfig = { - jsx: 'react' as any, - } + ` + const tsConfig = { + jsx: 'react' as any, + } beforeAll(() => { writeFileSync(fileName, source, 'utf8') @@ -223,8 +223,8 @@ describe('other jsx options', () => { }) describe('diagnostics', () => { - const fileName = 'test-typings.ts', - source = ` + const fileName = 'test-typings.ts' + const source = ` const f = (v: number) => v const t: string = f(5) ` @@ -299,8 +299,8 @@ const t: string = f(5) }) describe('source-maps', () => { - const fileName = 'source-maps-test.ts', - source = 'console.log("hello")' + const fileName = 'source-maps-test.ts' + const source = 'console.log("hello")' beforeAll(() => { writeFileSync(fileName, source, 'utf8') @@ -346,9 +346,9 @@ describe('source-maps', () => { }) describe('cannot compile', () => { - const fileName1 = 'test-cannot-compile.d.ts', - fileName2 = 'test-cannot-compile.jsx', - source = ` + const fileName1 = 'test-cannot-compile.d.ts' + const fileName2 = 'test-cannot-compile.jsx' + const source = ` interface Foo { a: string } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 21ec21b172..d4d925d643 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -12,8 +12,8 @@ import { cacheResolvedModules, hasOwn } from './compiler-utils' function doTypeChecking(configs: ConfigSet, fileName: string, program: _ts.Program, logger: Logger) { if (configs.shouldReportDiagnostic(fileName)) { - const sourceFile = program.getSourceFile(fileName), - diagnostics = program.getSemanticDiagnostics(sourceFile).concat(program.getSyntacticDiagnostics(sourceFile)) + const sourceFile = program.getSourceFile(fileName) + const diagnostics = program.getSemanticDiagnostics(sourceFile).concat(program.getSyntacticDiagnostics(sourceFile)) // will raise or just warn diagnostics depending on config configs.raiseDiagnostics(diagnostics, fileName, logger) } @@ -25,31 +25,33 @@ function doTypeChecking(configs: ConfigSet, fileName: string, program: _ts.Progr export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCache: MemoryCache): CompilerInstance => { logger.debug('compileUsingProgram(): create typescript compiler') - const ts = configs.compilerModule, - cwd = configs.cwd, - { options, projectReferences, errors } = configs.typescript, - incremental = configs.tsJest.incremental, - programDebugText = `${incremental ? 'incremental program' : 'program'}` + const ts = configs.compilerModule + const cwd = configs.cwd + const { options, projectReferences, errors } = configs.typescript + const incremental = configs.tsJest.incremental + const programDebugText = `${incremental ? 'incremental program' : 'program'}` + const cacheDir = configs.tsCacheDir const compilerHostTraceCtx = { - namespace: 'ts:compilerHost', - call: null, - [LogContexts.logLevel]: LogLevels.trace, - }, - sys = { - ...ts.sys, - readFile: logger.wrap(compilerHostTraceCtx, 'readFile', memoize(ts.sys.readFile)), - readDirectory: memoize(ts.sys.readDirectory), - getDirectories: memoize(ts.sys.getDirectories), - fileExists: memoize(ts.sys.fileExists), - directoryExists: memoize(ts.sys.directoryExists), - resolvePath: memoize(ts.sys.resolvePath), - realpath: memoize(ts.sys.realpath!), - getCurrentDirectory: () => cwd, - getNewLine: () => '\n', - getCanonicalFileName: (fileName: string) => - ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(), - } - let builderProgram: _ts.EmitAndSemanticDiagnosticsBuilderProgram, program: _ts.Program, host: _ts.CompilerHost + namespace: 'ts:compilerHost', + call: null, + [LogContexts.logLevel]: LogLevels.trace, + } + const sys = { + ...ts.sys, + readFile: logger.wrap(compilerHostTraceCtx, 'readFile', memoize(ts.sys.readFile)), + readDirectory: memoize(ts.sys.readDirectory), + getDirectories: memoize(ts.sys.getDirectories), + fileExists: memoize(ts.sys.fileExists), + directoryExists: memoize(ts.sys.directoryExists), + resolvePath: memoize(ts.sys.resolvePath), + realpath: memoize(ts.sys.realpath!), + getCurrentDirectory: () => cwd, + getNewLine: () => '\n', + getCanonicalFileName: (fileName: string) => (ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase()), + } + let builderProgram: _ts.EmitAndSemanticDiagnosticsBuilderProgram + let program: _ts.Program + let host: _ts.CompilerHost if (incremental) { host = ts.createIncrementalCompilerHost(options, sys) builderProgram = ts.createIncrementalProgram({ @@ -83,43 +85,43 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa }) } // Read and cache custom transformers. - const customTransformers = configs.tsCustomTransformers, - updateMemoryCache = (code: string, fileName: string): void => { - logger.debug({ fileName }, `updateMemoryCache(): update memory cache for ${programDebugText}`) + const customTransformers = configs.tsCustomTransformers + const updateMemoryCache = (code: string, fileName: string): void => { + logger.debug({ fileName }, `updateMemoryCache(): update memory cache for ${programDebugText}`) - const sourceFile = incremental ? builderProgram.getSourceFile(fileName) : program.getSourceFile(fileName) - if (!hasOwn.call(memoryCache.versions, fileName)) { - memoryCache.versions[fileName] = 1 - } - if (memoryCache.contents[fileName] !== code) { - memoryCache.contents[fileName] = code - memoryCache.versions[fileName] = (memoryCache.versions[fileName] || 0) + 1 + const sourceFile = incremental ? builderProgram.getSourceFile(fileName) : program.getSourceFile(fileName) + if (!hasOwn.call(memoryCache.versions, fileName)) { + memoryCache.versions[fileName] = 1 + } + if (memoryCache.contents[fileName] !== code) { + memoryCache.contents[fileName] = code + memoryCache.versions[fileName] = (memoryCache.versions[fileName] || 0) + 1 + } + // Update program when file changes. + if (sourceFile === undefined || sourceFile.text !== code || program.isSourceFileFromExternalLibrary(sourceFile)) { + const programOptions = { + rootNames: Object.keys(memoryCache.versions), + options, + host, + configFileParsingDiagnostics: errors, + projectReferences, } - // Update program when file changes. - if (sourceFile === undefined || sourceFile.text !== code || program.isSourceFileFromExternalLibrary(sourceFile)) { - const programOptions = { - rootNames: Object.keys(memoryCache.versions), - options, - host, - configFileParsingDiagnostics: errors, - projectReferences, - } - if (incremental) { - builderProgram = ts.createIncrementalProgram(programOptions) - program = builderProgram.getProgram() - } else { - program = ts.createProgram({ - ...programOptions, - oldProgram: program, - }) - } + if (incremental) { + builderProgram = ts.createIncrementalProgram(programOptions) + program = builderProgram.getProgram() + } else { + program = ts.createProgram({ + ...programOptions, + oldProgram: program, + }) } } + } return { compileFn: (code: string, fileName: string): SourceOutput => { - const normalizedFileName = normalize(fileName), - output: [string, string] = ['', ''] + const normalizedFileName = normalize(fileName) + const output: [string, string] = ['', ''] // Must set memory cache before attempting to read file. updateMemoryCache(code, normalizedFileName) const sourceFile = incremental @@ -153,31 +155,35 @@ export const compileUsingProgram = (configs: ConfigSet, logger: Logger, memoryCa logger.debug(`diagnoseFn(): computing diagnostics for ${normalizedFileName} using ${programDebugText}`) doTypeChecking(configs, normalizedFileName, program, logger) + /** + * We don't need the following logic with no cache run because no cache always gives correct typing + */ /* istanbul ignore next (covered by e2e) */ - if (micromatch.isMatch(normalizedFileName, configs.testMatchPatterns)) { - cacheResolvedModules(normalizedFileName, memoryCache, program, configs.tsCacheDir, logger) - } else { - /* istanbul ignore next (covered by e2e) */ - Object.entries(memoryCache.resolvedModules) - .filter(entry => { - /** - * When imported modules change, we only need to check whether the test file is compiled previously or not. - * Due to jest cache, our memory cache won't contain compiled result of test file so we are sure that we - * can do type checking on test file. By checking memory cache, we can avoid repeatedly doing type checking - * against test file for 1st time run after clearing cache. - */ - return ( - entry[1].find(modulePath => modulePath === normalizedFileName) && - !hasOwn.call(memoryCache.outputs, entry[0]) - ) - }) - .forEach(entry => { - logger.debug( - `diagnoseFn(): computing diagnostics for test file that imports ${normalizedFileName} using ${programDebugText}`, - ) - - doTypeChecking(configs, entry[0], program, logger) - }) + if (cacheDir) { + if (micromatch.isMatch(normalizedFileName, configs.testMatchPatterns)) { + cacheResolvedModules(normalizedFileName, memoryCache, program, cacheDir, logger) + } else { + /* istanbul ignore next (covered by e2e) */ + Object.entries(memoryCache.resolvedModules) + .filter(entry => { + /** + * When imported modules change, we only need to check whether the test file is compiled previously or not + * base on memory cache. By checking memory cache, we can avoid repeatedly doing type checking against + * test file for 1st time run after clearing cache because + */ + return ( + entry[1].find(modulePath => modulePath === normalizedFileName) && + !hasOwn.call(memoryCache.outputs, entry[0]) + ) + }) + .forEach(entry => { + logger.debug( + `diagnoseFn(): computing diagnostics for test file that imports ${normalizedFileName} using ${programDebugText}`, + ) + + doTypeChecking(configs, entry[0], program, logger) + }) + } } if (result.emitSkipped) { throw new TypeError(`${relative(cwd, fileName)}: Emit skipped`) diff --git a/src/compiler/transpile-module.spec.ts b/src/compiler/transpile-module.spec.ts index 855998628b..67e5d0cb71 100644 --- a/src/compiler/transpile-module.spec.ts +++ b/src/compiler/transpile-module.spec.ts @@ -17,8 +17,8 @@ describe('transpile module with isolatedModule: true', () => { }) it('should compile using transpileModule and not use cache', () => { - const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, tsConfig: false } }), - spy = jest.spyOn(require('typescript'), 'transpileModule') + const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, tsConfig: false } }) + const spy = jest.spyOn(require('typescript'), 'transpileModule') logTarget.clear() const compiled = compiler.compile('export default 42', __filename) @@ -40,11 +40,11 @@ describe('transpile module with isolatedModule: true', () => { }) it('should compile js file for allowJs true', () => { - const fileName = `${__filename}.test.js`, - compiler = makeCompiler({ - tsJestConfig: { ...baseTsJestConfig, tsConfig: { allowJs: true, outDir: '$$ts-jest$$' } }, - }), - source = 'export default 42' + const fileName = `${__filename}.test.js` + const compiler = makeCompiler({ + tsJestConfig: { ...baseTsJestConfig, tsConfig: { allowJs: true, outDir: '$$ts-jest$$' } }, + }) + const source = 'export default 42' writeFileSync(fileName, source, 'utf8') const compiled = compiler.compile(source, fileName) @@ -55,16 +55,16 @@ describe('transpile module with isolatedModule: true', () => { }) it('should compile tsx file for jsx preserve', () => { - const fileName = `foo.tsx`, - compiler = makeCompiler({ - tsJestConfig: { - ...baseTsJestConfig, - tsConfig: { - jsx: 'preserve' as any, - }, + const fileName = `foo.tsx` + const compiler = makeCompiler({ + tsJestConfig: { + ...baseTsJestConfig, + tsConfig: { + jsx: 'preserve' as any, }, - }), - source = ` + }, + }) + const source = ` const App = () => { return <>Test } @@ -79,16 +79,16 @@ describe('transpile module with isolatedModule: true', () => { }) it('should compile tsx file for other jsx options', () => { - const fileName = `foo.tsx`, - compiler = makeCompiler({ - tsJestConfig: { - ...baseTsJestConfig, - tsConfig: { - jsx: 'react' as any, - }, + const fileName = `foo.tsx` + const compiler = makeCompiler({ + tsJestConfig: { + ...baseTsJestConfig, + tsConfig: { + jsx: 'react' as any, }, - }), - source = ` + }, + }) + const source = ` const App = () => { return <>Test } @@ -103,8 +103,8 @@ describe('transpile module with isolatedModule: true', () => { }) it('should have correct source maps', () => { - const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, tsConfig: false } }), - source = 'const f = (v: number) => v\nconst t: number = f(5)' + const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, tsConfig: false } }) + const source = 'const f = (v: number) => v\nconst t: number = f(5)' const compiled = compiler.compile(source, __filename) diff --git a/src/compiler/transpile-module.ts b/src/compiler/transpile-module.ts index 8d04ad94e9..cc7cb6c2cb 100644 --- a/src/compiler/transpile-module.ts +++ b/src/compiler/transpile-module.ts @@ -14,13 +14,13 @@ export const compileUsingTranspileModule = (configs: ConfigSet, logger: Logger): compileFn: (code: string, fileName: string): SourceOutput => { logger.debug({ fileName }, 'getOutput(): compiling as isolated module') - const normalizedFileName = normalize(fileName), - result = configs.compilerModule.transpileModule(code, { - fileName: normalizedFileName, - transformers: configs.tsCustomTransformers, - compilerOptions: configs.typescript.options, - reportDiagnostics: configs.shouldReportDiagnostic(normalizedFileName), - }) + const normalizedFileName = normalize(fileName) + const result = configs.compilerModule.transpileModule(code, { + fileName: normalizedFileName, + transformers: configs.tsCustomTransformers, + compilerOptions: configs.typescript.options, + reportDiagnostics: configs.shouldReportDiagnostic(normalizedFileName), + }) if (result.diagnostics && configs.shouldReportDiagnostic(normalizedFileName)) { configs.raiseDiagnostics(result.diagnostics, normalizedFileName, logger) diff --git a/src/ts-jest-transformer.ts b/src/ts-jest-transformer.ts index e3247ea84b..d4e7514706 100644 --- a/src/ts-jest-transformer.ts +++ b/src/ts-jest-transformer.ts @@ -18,18 +18,6 @@ interface ConfigSetIndexItem { jestConfig: JsonableValue } -function checkDefinitionFile(filePath: string): boolean { - return filePath.endsWith('.d.ts') -} - -function checkJsFile(filePath: string): boolean { - return /\.jsx?$/.test(filePath) -} - -function checkTsFile(filePath: string): boolean { - return !checkDefinitionFile(filePath) && /\.tsx?$/.test(filePath) -} - export class TsJestTransformer implements Transformer { /** * @internal @@ -114,14 +102,14 @@ export class TsJestTransformer implements Transformer { this.logger.debug({ fileName: filePath, transformOptions }, 'processing', filePath) let result: string | TransformedSource - const source: string = input, - configs = this.configsFor(jestConfig), - { hooks } = configs, - stringify = configs.shouldStringifyContent(filePath), - babelJest = stringify ? undefined : configs.babelJestTransformer, - isDefinitionFile = checkDefinitionFile(filePath), - isJsFile = checkJsFile(filePath), - isTsFile = checkTsFile(filePath) + const source: string = input + const configs = this.configsFor(jestConfig) + const { hooks } = configs + const stringify = configs.shouldStringifyContent(filePath) + const babelJest = stringify ? undefined : configs.babelJestTransformer + const isDefinitionFile = filePath.endsWith('.d.ts') + const isJsFile = /\.jsx?$/.test(filePath) + const isTsFile = !isDefinitionFile && /\.tsx?$/.test(filePath) if (stringify) { // handles here what we should simply stringify result = `module.exports=${JSON.stringify(source)}` diff --git a/tslint.json b/tslint.json index e21fb54d77..7669513b00 100644 --- a/tslint.json +++ b/tslint.json @@ -47,7 +47,6 @@ "no-string-throw": true, "no-var-keyword": true, "object-literal-sort-keys": false, - "one-variable-per-declaration": false, "ordered-imports": [ true, { From 145a7e230b1c8e2638e51bb070b2ab6d115885a0 Mon Sep 17 00:00:00 2001 From: Ahn Date: Thu, 2 Apr 2020 09:35:32 +0200 Subject: [PATCH 3/3] fix: fix snapshots for unsupported version diagnostic tests --- e2e/__tests__/__snapshots__/diagnostics.test.ts.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap b/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap index a0953cf8bc..aba886485f 100644 --- a/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap +++ b/e2e/__tests__/__snapshots__/diagnostics.test.ts.snap @@ -143,7 +143,7 @@ exports[`With diagnostics throw using incremental program with unsupported versi TypeError: ts.createIncrementalCompilerHost is not a function - at Object.exports.compileUsingProgram (../../__templates__/with-typescript-2-7/node_modules/ts-jest/dist/compiler/program.js:40:19) + at Object.exports.compileUsingProgram (../../__templates__/with-typescript-2-7/node_modules/ts-jest/dist/compiler/program.js:47:19) Test Suites: 1 failed, 1 total Tests: 0 total @@ -165,7 +165,7 @@ exports[`With diagnostics throw using incremental program with unsupported versi TypeError: ts.createIncrementalCompilerHost is not a function - at Object.exports.compileUsingProgram (../../__templates__/with-unsupported-version/node_modules/ts-jest/dist/compiler/program.js:40:19) + at Object.exports.compileUsingProgram (../../__templates__/with-unsupported-version/node_modules/ts-jest/dist/compiler/program.js:47:19) Test Suites: 1 failed, 1 total Tests: 0 total @@ -662,7 +662,7 @@ exports[`With diagnostics warn only using incremental program with unsupported v TypeError: ts.createIncrementalCompilerHost is not a function - at Object.exports.compileUsingProgram (../../__templates__/with-typescript-2-7/node_modules/ts-jest/dist/compiler/program.js:40:19) + at Object.exports.compileUsingProgram (../../__templates__/with-typescript-2-7/node_modules/ts-jest/dist/compiler/program.js:47:19) Test Suites: 1 failed, 1 total Tests: 0 total @@ -684,7 +684,7 @@ exports[`With diagnostics warn only using incremental program with unsupported v TypeError: ts.createIncrementalCompilerHost is not a function - at Object.exports.compileUsingProgram (../../__templates__/with-unsupported-version/node_modules/ts-jest/dist/compiler/program.js:40:19) + at Object.exports.compileUsingProgram (../../__templates__/with-unsupported-version/node_modules/ts-jest/dist/compiler/program.js:47:19) Test Suites: 1 failed, 1 total Tests: 0 total