umi修改默认jest配置

983 阅读3分钟

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配置文档)

  1. 通过看源码以及黑到的 config,可知源码里面require.resolve给出以require形式引包的字符串对应的模块路径。现在抽出来放根目录了,也得改一下
  2. args.package用来表明多包应用测试哪个包,是通过 umi 命令传进来的。这里去掉了args层,而且我这个也不是多包项目,所以先废了这个功能。如果有大佬知道怎么整上,还望指出
  3. 我在这里加入了一个setupTest.tsx文件,直接给添上了。
  4. 这个就是按照jest文档进行配置的方法,具体配置看文档,上面有个链接。该配置也继承了umi的默认配置。
  5. 最后那句 console.log 是我拿来做特殊标记,来证明这个配置生效了。

然后把package.jsonnpm test命令改成jest,就完成了。

相应的,test: coverage可以改成jest --coverage

然后运行测试就🆗了。

另注:如果是使用 dumi 开发组件库,打包时还会把jest.config.ts编译出.d.ts给打包进去。这个是不应该出现的
目前去 father 搜了一圈发现没有提供这样的配置,但是一想为什么.umirc.ts这类文件没被打包; 所以使用了最简单的办法:jest.config.ts前面加一个点,测试命令也加上--config .jest.config.ts。虽然这个方法很土,但有效。(如果有更好的方式请大佬不吝赐教)