1 | const yargs = require('yargs');
|
2 | const jest = require('jest-cli');
|
3 | const jestOptions = require('jest-cli/build/cli/args').options;
|
4 | const { omit } = require('ramda');
|
5 | const merge = require('deepmerge');
|
6 | const loaderMerge = require('neutrino-middleware-loader-merge');
|
7 | const { isAbsolute, join } = require('path');
|
8 | const { tmpdir } = require('os');
|
9 | const { writeFileSync } = require('fs');
|
10 |
|
11 | const mediaNames = '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$';
|
12 | const styleNames = '\\.(css|less|sass|scss)$';
|
13 | const jsNames = '\\.(js|jsx)$';
|
14 |
|
15 | function 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 |
|
25 | function 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 |
|
71 | module.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 |
|
97 |
|
98 |
|
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 |
|
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 | };
|