Skip to content
This repository was archived by the owner on Aug 12, 2020. It is now read-only.

Commit 1e645fe

Browse files
authored
Merge pull request #39 from NLeSC/coverage-ts-jest-17
Using ts-jest for coverage
2 parents 45caeba + 171504f commit 1e645fe

File tree

5 files changed

+67
-29
lines changed

5 files changed

+67
-29
lines changed

packages/react-scripts/config/jest/transform.js

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,66 @@
66
* of patent rights can be found in the PATENTS file in the same directory.
77
*/
88

9+
// This file is a merger between the original transform.js and ts-jest/dist/preprocessor.js (https://github.com/kulshekhar/ts-jest/blob/e1f95e524ed62091736f70abf63530f1f107ec03/src/preprocessor.ts)
10+
// The preprocessor from ts-jest could not be used directly,
11+
// because it did not use babel and
12+
// could not get configuration from the right place (../utils/createJestConfig.js)
13+
// instead it was retrieved from of argv which was incomplete
14+
915
const babelJest = require('babel-jest');
1016
const tsc = require('typescript');
17+
const glob = require('glob-all');
18+
const nodepath = require('path');
19+
const tsJestUtils = require('ts-jest/dist/utils');
20+
const getPackageRoot = require('jest-util').getPackageRoot;
21+
const root = getPackageRoot();
1122

1223
const babelTransformer = babelJest.createTransformer({
1324
presets: [require.resolve('babel-preset-react-app')]
1425
});
1526

16-
// TODO load tsconfig.json in created app instead of duplicating tsconfig.compilerOptions here
17-
const compilerOptions = {
18-
// Overwrite module
19-
// Jest gives `SyntaxError: Unexpected token import` error when ES6 module are emitted
20-
// module: tsc.ModuleKind.ES6,
21-
module: tsc.ModuleKind.CommonJS,
22-
// Overwrite jsx
23-
// Expected Babel transformer to convert jsx to js
24-
// but Jest gives `SyntaxError: Unexpected token <` error when set to Preserve
25-
// jsx: tsc.JsxEmit.Preserve,
26-
jsx: tsc.JsxEmit.React,
27-
target: tsc.ScriptTarget.ES6,
28-
moduleResolution: tsc.ModuleResolutionKind.NodeJs,
29-
};
27+
function initializeCache(config) {
28+
const collectCoverage = config.collectCoverage;
29+
const coverageDirectory = config.coverageDirectory;
30+
const coverageReporters = config.coverageReporters;
31+
const collectCoverageFrom = config.collectCoverageFrom;
32+
const testResultsProcessor = config.testResultsProcessor;
33+
global.__ts_coverage__cache__ = {};
34+
global.__ts_coverage__cache__.sourceCache = {};
35+
global.__ts_coverage__cache__.coverageConfig = { collectCoverage: collectCoverage, coverageDirectory: coverageDirectory, coverageReporters: coverageReporters };
36+
global.__ts_coverage__cache__.coverageCollectFiles =
37+
collectCoverage &&
38+
testResultsProcessor &&
39+
collectCoverageFrom &&
40+
collectCoverageFrom.length ?
41+
glob.sync(collectCoverageFrom).map(function (x) { return nodepath.resolve(root, x); }) : [];
42+
}
43+
44+
function tsProcess(src, path, config) {
45+
if (path.endsWith('.ts') || path.endsWith('.tsx')) {
46+
if (config.testResultsProcessor && !global.__ts_coverage__cache__) {
47+
// initialize only once
48+
initializeCache(config);
49+
}
50+
var transpiled = tsc.transpileModule(src, {
51+
compilerOptions: tsJestUtils.getTSConfig(config.globals, config.collectCoverage),
52+
fileName: path
53+
});
54+
if (global.__ts_coverage__cache__) {
55+
if (!config.testRegex || !path.match(config.testRegex)) {
56+
global.__ts_coverage__cache__.sourceCache[path] = transpiled.outputText;
57+
}
58+
}
59+
var modified = "require('ts-jest').install();" + transpiled.outputText;
60+
return modified;
61+
}
62+
return src;
63+
}
3064

3165
// transpile the source with TypeScript, if needed, and then with Babel
3266
module.exports = {
33-
process(src, path) {
34-
if (path.endsWith('.ts') || path.endsWith('.tsx')) {
35-
src = tsc.transpile(
36-
src,
37-
compilerOptions,
38-
path,
39-
[]
40-
);
41-
}
67+
process(src, path, config) {
68+
src = tsProcess(src, path, config);
4269
return babelTransformer.process(src, path);
4370
},
4471
};

packages/react-scripts/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"style-loader": "0.13.1",
6767
"tslint": "^3.15.1",
6868
"tslint-loader": "^2.1.5",
69+
"ts-jest": "^0.1.13",
6970
"typescript": "^2.0.7",
7071
"url-loader": "0.5.7",
7172
"webpack": "1.13.2",

packages/react-scripts/template/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,8 @@ Run `npm test -- --coverage` (note extra `--` in the middle) to include a covera
805805
806806
Note that tests run much slower with coverage so it is recommended to run it separately from your normal workflow.
807807
808+
The coverage can be found in the `coverage/remapped/` directory in different formats like html and lcov.
809+
808810
### Continuous Integration
809811
810812
By default `npm test` runs the watcher with interactive CLI. However, you can force it to run tests once and finish the process by setting an environment variable called `CI`. Popular CI servers already set it by default but you can do this yourself too:

packages/react-scripts/template/src/App.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import * as ReactDOM from 'react-dom';
33

4-
import App from './App';
4+
import { App } from './App';
55

66
it('renders without crashing', () => {
77
const div = document.createElement('div');

packages/react-scripts/utils/createJestConfig.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,20 @@
1111

1212
const pathExists = require('path-exists');
1313
const paths = require('../config/paths');
14+
const path = require('path');
1415

1516
module.exports = (resolve, rootDir, isEjecting) => {
1617
// Use this instead of `paths.testsSetup` to avoid putting
1718
// an absolute filename into configuration after ejecting.
1819
const setupTestsFile = pathExists.sync(paths.testsSetup) ? '<rootDir>/src/setupTests.js' : undefined;
1920

21+
const compilerOptions = require(path.resolve('./tsconfig.json')).compilerOptions;
22+
// Jest gives `SyntaxError: Unexpected token import` error when ES6 module are emitted
23+
compilerOptions.module = "commonjs";
24+
// Expected Babel transformer to convert jsx to js
25+
// but Jest gives `SyntaxError: Unexpected token <` error when set to preserve
26+
compilerOptions.jsx = "react";
27+
2028
const config = {
2129
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
2230
moduleFileExtensions: ['jsx', 'js', 'json', 'ts', 'tsx'],
@@ -29,14 +37,14 @@ module.exports = (resolve, rootDir, isEjecting) => {
2937
testPathIgnorePatterns: ['<rootDir>/(build|docs|node_modules)/'],
3038
testEnvironment: 'node',
3139
testRegex: "(/__tests__/.*|\.(test|spec))\.(ts|tsx|js|jsx)$",
40+
testResultsProcessor: require.resolve("ts-jest/coverageprocessor"),
41+
scriptPreprocessor: resolve('config/jest/transform.js'),
42+
globals: {
43+
"__TS_CONFIG__": compilerOptions
44+
}
3245
};
3346
if (rootDir) {
3447
config.rootDir = rootDir;
3548
}
36-
if (!isEjecting) {
37-
// This is unnecessary after ejecting because Jest
38-
// will just use .babelrc in the project folder.
39-
config.scriptPreprocessor = resolve('config/jest/transform.js');
40-
}
4149
return config;
4250
};

0 commit comments

Comments
 (0)