UNPKG

3.85 kBJavaScriptView Raw
1const yargs = require('yargs');
2const jest = require('jest-cli');
3const jestOptions = require('jest-cli/build/cli/args').options;
4const { omit } = require('ramda');
5const merge = require('deepmerge');
6const loaderMerge = require('neutrino-middleware-loader-merge');
7const { isAbsolute, join } = require('path');
8const { tmpdir } = require('os');
9const { writeFileSync } = require('fs');
10
11const mediaNames = '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$';
12const styleNames = '\\.(css|less|sass|scss)$';
13const jsNames = '\\.(js|jsx)$';
14
15function getFinalPath(path) {
16 if (isAbsolute(path)) {
17 return path;
18 }
19
20 return path.startsWith('.') ?
21 join('<rootDir>', path) :
22 join('<rootDir>', 'node_modules', path);
23}
24
25function normalizeJestOptions(opts, neutrino) {
26 const aliases = neutrino.config.resolve.alias.entries() || {};
27 const moduleNames = Object
28 .keys(aliases)
29 .reduce((mapper, key) => Object.assign(mapper, {
30 [`${key}(.*)`]: `${getFinalPath(aliases[key])}$1`
31 }), {});
32 const moduleNameMapper = merge({
33 [mediaNames]: require.resolve('./file-mock'),
34 [styleNames]: require.resolve('./style-mock')
35 }, moduleNames);
36 const moduleDirectories = [...new Set([
37 join(__dirname, '../node_modules'),
38 ...(opts.moduleDirectories || []),
39 ...neutrino.config.resolve.modules.values()
40 ])];
41 const moduleFileExtensions = [...new Set([
42 'js',
43 'jsx',
44 ...(opts.moduleFileExtensions || []),
45 ...neutrino.config.resolve.extensions.values().map(e => e.replace('.', ''))
46 ])];
47
48 return merge.all([
49 {
50 moduleDirectories,
51 moduleFileExtensions,
52 moduleNameMapper,
53 bail: true,
54 roots: [neutrino.options.tests],
55 testRegex: '(_test|_spec|\\.test|\\.spec)\\.jsx?$',
56 transform: { [jsNames]: require.resolve('./transformer') },
57 globals: {
58 BABEL_OPTIONS: omit(
59 ['cacheDirectory'],
60 neutrino.config.module
61 .rule('compile')
62 .use('babel')
63 .get('options')
64 )
65 }
66 },
67 opts
68 ]);
69}
70
71module.exports = (neutrino, opts = {}) => {
72 neutrino.config.when(neutrino.config.module.rules.has('lint'), () => neutrino
73 .use(loaderMerge('lint', 'eslint'), {
74 plugins: ['jest'],
75 envs: ['jest/globals'],
76 rules: {
77 'jest/no-disabled-tests': 'warn',
78 'jest/no-focused-tests': 'error',
79 'jest/no-identical-title': 'error',
80 'jest/valid-expect': 'error'
81 }
82 }));
83
84 neutrino.on('test', (args) => {
85 neutrino.use(loaderMerge('compile', 'babel'), {
86 env: {
87 test: {
88 retainLines: true,
89 presets: [require.resolve('babel-preset-jest')],
90 plugins: [require.resolve('babel-plugin-transform-es2015-modules-commonjs')]
91 }
92 }
93 });
94
95 return new Promise((resolve, reject) => {
96 // We need to parse argv separately in order to identify files
97 // and jest-related options since root neutrino does not know about
98 // jest options and will provide wrong/incomplete `args.files`
99 const jestArgs = yargs
100 .command('test [files..]', 'Run tests', jestOptions)
101 .argv;
102 const configFile = join(tmpdir(), 'config.json');
103 const options = normalizeJestOptions(opts, neutrino);
104 const cliOptions = Object.assign(
105 jestArgs,
106 {
107 // Jest is looking for Array of files in `argv._`. Providing them
108 _: jestArgs.files,
109 config: configFile,
110 coverage: args.coverage,
111 watch: args.watch
112 }
113 );
114
115 writeFileSync(configFile, `${JSON.stringify(options, null, 2)}\n`);
116
117 jest.runCLI(cliOptions, options.roots, result =>
118 (result.numFailedTests || result.numFailedTestSuites ?
119 reject() :
120 resolve()));
121 });
122 });
123};