umijs 没有给出如何操作 jest 配置,得自己搞。这里讲如何继承并修改 umijs 默认的jest配置
@umijs/test 探索
umi 对测试的默认配置是通过@umijs/test包给的配置来测试的。通过 jest 框架。
这个包的目录结构长这样:
很容易看出,createDefaultConfig.ts是创建 jest 配置的文件。
发现它传入两个参数,分别是cwd: string, args: IUmiTestArgs的一个函数,生成 jest 配置。
cwd很明显是当前工作路径,下面看args是什么类型:
export interface IUmiTestArgs extends Partial<ArgsType<typeof runCLI>['0']> {
version?: boolean;
cwd?: string;
debug?: boolean;
e2e?: boolean; // 是否支持 e2e 中缀(默认支持 spec, test)。下面可看出只有它有默认值为 true
package?: string; // 对 lerna 多包项目测试时,测试的包名
}
可以看出,它是继承自测试命令的参数。这里先忽略继承的 runCLI 函数的参数有什么用(若有必要作用,在这里忽略了,请大佬补充),只看这5个,然后扒一下bin目录里面umi-test.js看默认值:
const args = yParser(process.argv.slice(2), {
alias: {
watch: ['w'],
version: ['v'],
},
boolean: ['coverage', 'watch', 'version', 'debug', 'e2e'],
default: {
e2e: true,
},
});
看得出来,这五个字段是参数,默认只有 e2e 为 true。简单看了下源代码,生成配置用的参数注释到了上面。
export default function (cwd: string, args: IUmiTestArgs) {
const testMatchTypes = ['spec', 'test'];
if (args.e2e) {
testMatchTypes.push('e2e');
}
const isLerna = isLernaPackage(cwd);
const hasPackage = isLerna && args.package;
const testMatchPrefix = hasPackage ? `**/packages/${args.package}/` : '';
const hasSrc = existsSync(join(cwd, 'src'));
if (hasPackage) {
assert(
existsSync(join(cwd, 'packages', args.package!)),
`You specified --package, but packages/${args.package} does not exists.`,
);
}
return {
collectCoverageFrom: [
'index.{js,jsx,ts,tsx}',
hasSrc && 'src/**/*.{js,jsx,ts,tsx}',
isLerna && !args.package && 'packages/*/src/**/*.{js,jsx,ts,tsx}',
isLerna &&
args.package &&
`packages/${args.package}/src/**/*.{js,jsx,ts,tsx}`,
'!**/typings/**',
'!**/types/**',
'!**/fixtures/**',
'!**/examples/**',
'!**/*.d.ts',
].filter(Boolean),
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json'],
moduleNameMapper: {
'\.(css|less|sass|scss|stylus)$': require.resolve('identity-obj-proxy'),
},
setupFiles: [require.resolve('../../helpers/setupFiles/shim')],
setupFilesAfterEnv: [require.resolve('../../helpers/setupFiles/jasmine')],
testEnvironment: require.resolve('jest-environment-jsdom-fourteen'),
testMatch: [
`${testMatchPrefix}**/?*.(${testMatchTypes.join('|')}).(j|t)s?(x)`,
],
testPathIgnorePatterns: ['/node_modules/', '/fixtures/'],
transform: {
'^.+\.(js|jsx|ts|tsx)$': require.resolve(
'../../helpers/transformers/javascript',
),
'^.+\.(css|less|sass|scss|stylus)$': require.resolve(
'../../helpers/transformers/css',
),
'^(?!.*\.(js|jsx|ts|tsx|css|less|sass|scss|stylus|json)$)':
require.resolve('../../helpers/transformers/file'),
},
verbose: true,
transformIgnorePatterns: [
// 加 [^/]*? 是为了兼容 tnpm 的目录结构
// 比如:_umi-test@1.5.5@umi-test
// `node_modules/(?!([^/]*?umi|[^/]*?umi-test)/)`,
],
// 用于设置 jest worker 启动的个数
...(process.env.MAX_WORKERS
? { maxWorkers: Number(process.env.MAX_WORKERS) }
: {}),
};
}
然后在自己的 node_modules 里面黑一下对应的 js 文件,把生成的参数拿出来看看:
config = {
collectCoverageFrom: [
'index.{js,jsx,ts,tsx}',
'src/**/*.{js,jsx,ts,tsx}',
'!**/typings/**',
'!**/types/**',
'!**/fixtures/**',
'!**/examples/**',
'!**/*.d.ts'
],
moduleFileExtensions: [ 'js', 'jsx', 'ts', 'tsx', 'json' ],
moduleNameMapper: {
'\.(css|less|sass|scss|stylus)$': 'E:\Front-end\json-schemaeditor-antd\node_modules\identity-obj-proxy\src\index.js'
},
setupFiles: [
'E:\Front-end\json-schemaeditor-antd\node_modules\@umijs\test\helpers\setupFiles\shim.js'
],
setupFilesAfterEnv: [
'E:\Front-end\json-schemaeditor-antd\node_modules\@umijs\test\helpers\setupFiles\jasmine.js'
],
testEnvironment: 'E:\Front-end\json-schemaeditor-antd\node_modules\jest-environment-jsdom-fourteen\lib\index.js',
testMatch: [ '**/?*.(spec|test|e2e).(j|t)s?(x)' ],
testPathIgnorePatterns: [ '/node_modules/', '/fixtures/' ],
transform: {
'^.+\.(js|jsx|ts|tsx)$': 'E:\Front-end\json-schemaeditor-antd\node_modules\@umijs\test\helpers\transformers\javascript.js',
'^.+\.(css|less|sass|scss|stylus)$': 'E:\Front-end\json-schemaeditor-antd\node_modules\@umijs\test\helpers\transformers\css.js',
'^(?!.*\.(js|jsx|ts|tsx|css|less|sass|scss|stylus|json)$)': 'E:\Front-end\json-schemaeditor-antd\node_modules\@umijs\test\helpers\transformers\file.js'
},
verbose: true,
transformIgnorePatterns: []
}
继承并加入自己的 jest 配置
接下来,因为配置在 node_modules 里面,所以不能直接写。想要设置这个配置,得自己配置 jest.config.ts 用来当 jest 的配置,架空 umi 默认的 umi-test 命令。
正好,给它抽离一下复制到自己的 jest.config.ts 里面,如下:
// @ts-ignore
import { isLernaPackage } from '@umijs/utils';
import { existsSync } from 'fs';
import { join } from 'path';
import type {Config} from '@jest/types';
const testMatchTypes = ['spec', 'test', 'e2e'];
const isLerna = isLernaPackage(process.cwd());
const hasPackage = false;
const testMatchPrefix = hasPackage ? `**/packages/1/` : '';
const hasSrc = existsSync(join(process.cwd(), 'src'));
const config: Config.InitialOptions = {
collectCoverageFrom: [
'index.{js,jsx,ts,tsx}',
hasSrc && 'src/**/*.{js,jsx,ts,tsx}',
isLerna && 'packages/*/src/**/*.{js,jsx,ts,tsx}',
'!**/typings/**',
'!**/types/**',
'!**/fixtures/**',
'!**/examples/**',
'!**/*.d.ts',
].filter(dict => typeof dict === 'string') as string[],
coveragePathIgnorePatterns: [
"/node_modules/",
".umi",
".umi-production",
'demos'
],
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json'],
moduleNameMapper: {
'\.(css|less|sass|scss|stylus)$': require.resolve('identity-obj-proxy'),
},
setupFiles: [require.resolve('@umijs/test/helpers/setupFiles/shim'),
require.resolve('./config/test/setupTest')],
setupFilesAfterEnv: [require.resolve('@umijs/test/helpers/setupFiles/jasmine')],
testEnvironment: require.resolve('jest-environment-jsdom-fourteen'),
testMatch: [
`${testMatchPrefix}**/?*.(${testMatchTypes.join('|')}).(j|t)s?(x)`,
],
testPathIgnorePatterns: ['/node_modules/', '/fixtures/'],
transform: {
'^.+\.(js|jsx|ts|tsx)$': require.resolve(
'@umijs/test/helpers/transformers/javascript',
),
'^.+\.(css|less|sass|scss|stylus)$': require.resolve(
'@umijs/test/helpers/transformers/css',
),
'^(?!.*\.(js|jsx|ts|tsx|css|less|sass|scss|stylus|json)$)':
require.resolve('@umijs/test/helpers/transformers/file'),
},
verbose: true,
transformIgnorePatterns: [
// 加 [^/]*? 是为了兼容 tnpm 的目录结构
// 比如:_umi-test@1.5.5@umi-test
// `node_modules/(?!([^/]*?umi|[^/]*?umi-test)/)`,
],
// 用于设置 jest worker 启动的个数
...(process.env.MAX_WORKERS
? { maxWorkers: Number(process.env.MAX_WORKERS) }
: {}),
};
console.log('cpu-pro: 已使用 jest.config.ts 作为 jest 配置文件。');
export default config
主要的说明(jest配置文档)
- 通过看源码以及黑到的 config,可知源码里面
require.resolve给出以require形式引包的字符串对应的模块路径。现在抽出来放根目录了,也得改一下 args.package用来表明多包应用测试哪个包,是通过 umi 命令传进来的。这里去掉了args层,而且我这个也不是多包项目,所以先废了这个功能。如果有大佬知道怎么整上,还望指出- 我在这里加入了一个
setupTest.tsx文件,直接给添上了。 - 这个就是按照
jest文档进行配置的方法,具体配置看文档,上面有个链接。该配置也继承了umi的默认配置。 - 最后那句 console.log 是我拿来做特殊标记,来证明这个配置生效了。
然后把package.json的npm test命令改成jest,就完成了。
相应的,test: coverage可以改成jest --coverage。
然后运行测试就🆗了。
另注:如果是使用 dumi 开发组件库,打包时还会把
jest.config.ts编译出.d.ts给打包进去。这个是不应该出现的
目前去 father 搜了一圈发现没有提供这样的配置,但是一想为什么.umirc.ts这类文件没被打包; 所以使用了最简单的办法:jest.config.ts前面加一个点,测试命令也加上--config .jest.config.ts。虽然这个方法很土,但有效。(如果有更好的方式请大佬不吝赐教)