/
jestAssetTransformer.mjs
85 lines (74 loc) · 3.71 KB
/
jestAssetTransformer.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import path from 'path';
import JestCssModulesTransformer from 'jest-css-modules-transform';
import { FileTypeRegexes } from '../utils/index.js';
/** @type {import('@jest/core/node_modules/@jest/transform/build/types').SyncTransformer} */
const jestAssetTransformer = {
/**
* Processes source file contents to be usable in jest tests.
* Since jest can't parse/understand all file types even after setting certain config
* values, this transformer file helps to transpile and/or reformat the code that will
* be outputted to jest test suites/files.
*
* Note: Cannot use `export default`, must use `module.exports` since this is `process()`, not `processAsync()`.
*
* @param {string} srcFileContents - Contents of the original source file, whether as a string or bytes.
* @param {string} srcAbsPath - Absolute path to the source file.
* @param {Object} options
* @param {Object} options.config - Jest configuration options from jest.config.json, package.json->jest, etc.
* @param {Object} options.transformerConfig - Configuration options for this specific transformer, passed in jestConfig->transform.
* @returns {import('@jest/types/build/Transform').TransformResult}
*/
process(srcFileContents, srcAbsPath, options) {
const srcText = JSON.stringify(srcFileContents);
const srcFileName = JSON.stringify(path.basename(srcAbsPath));
const {
config: jestConfigs,
transformerConfig: transformerConfigs,
} = options;
if (FileTypeRegexes.Text.test(srcAbsPath)) {
/**
* Text files are processed by webpack to import the file content directly as a string,
* so reflect that in jest tests by exporting the stringified file contents.
*/
return {
code: `module.exports = ${srcText};`,
};
}
if (FileTypeRegexes.Svg.test(srcAbsPath)) {
/**
* Mimic default (URL) and named (React.Component) exports from @svgr.
*
* Note that the String constructor must be used so we can set new fields on it in order to have both
* default/named exports because you can't set new fields on string primitives.
* i.e. let str = 'Hi'; str.myField = 'Bye'; --> str.myField == null
*/
return {
code: `
const React = require('react');
module.exports = new String(${srcFileName});
module.exports.ReactComponent = React.forwardRef((props, ref) => React.createElement('svg', { ref, ...props }));
`,
};
}
if (FileTypeRegexes.Styles.test(srcAbsPath)) {
/**
* `jest-css-modules-transform` has a bug where they [don't support jest@>=27]{@link https://github.com/Connormiha/jest-css-modules-transform/issues/39}.
* So nest its call here to get the config option they are supposed to use until the bug is fixed.
*
* Another possible option: [postcss-modules-scope]{@link https://www.npmjs.com/package/postcss-modules-scope}
*/
const allTranspiledCssCode = JestCssModulesTransformer.process(srcFileContents, srcAbsPath, jestConfigs);
return {
code: allTranspiledCssCode,
};
}
/**
* Binary files (images, fonts, etc.) are processed by webpack to use URLs instead of file content,
* so reflect that in jest tests by exporting only the name to form a "pretend" URL.
*/
return {
code: `module.exports = ${srcFileName};`,
};
},
};
export default jestAssetTransformer;