1

我经历了 Karma 测试运行器的“启动”时间非常慢,在分析运行后,我意识到最大的减速是由源映射的创建引起的。

更具体地说,假设我使用karma-webpackwebpack 作为预处理器,每次 karma 加载测试文件时,它都会被馈送到 webpack 为其生成源映射。

鉴于我没有拆分/分块我的应用程序和供应商代码,每个测试文件都获得相同的供应商源映射(内联)。

我认为我可以通过简单地防止node_modules/文件发生源映射来解决此问题,但意识到您只能根据最终资产文件而不是输入源/模块文件来排除文件获取源映射。

所以我发现这个插件可以自动将我的应用程序和供应商代码拆分成单独的块(而不是必须手动列出每个供应商模块)。

然而,我在运行 Karma 时开始出现此错误: ReferenceError: Can't find variable: webpackJsonp

我很确定这是因为 Karma 没有意识到供应商和应用程序代码被分成单独的块,因此只包括使用该files选项配置的代码(即测试文件本身而不是供应商文件)。

似乎在files预处理每个测试文件之前解析和处理了该配置选项,这意味着我认为不可能在files选项中指定供应商块,因为 Karma 在尝试时不会知道它寻找它(为时过早)。

我能看到的唯一解决方案是:

  • 更改 Karma 的实现方式,使其可以处理供应商和应用程序块文件的分离。
  • 不要使用karma-webpack和预处理,而是在测试模式下构建应用程序,然后运行测试构建目录的 Karma(以便供应商块足够早地存在)。

有没有我错过的解决方案?

我觉得奇怪,这似乎不是一个常见的问题。

编辑 1

我找到了这个,但是那里的人建议在 webpack 配置中使用多个入口点(即一个用于应用程序,一个用于供应商)。我会尝试看看这是否适用于 Karma,但它仍然有一个很大的缺点(在我看来)你必须手动跟踪你放入vendor数组中的内容。即每次你安装一个包你必须把它添加到数组中,反之亦然。

编辑 2

在我将源映射 webpack 插件配置为排除供应商文件之前,使用多个入口点(在 webpack 配置中)甚至不起作用(而它会使用webpack-split-by-path插件)。

我将尝试实施“先构建后测试”的方法。

4

1 回答 1

1

如果其他人遇到这个问题,我得到了“构建然后休息”的方法,即我放弃了karma-webpackKarma 预处理,转而支持单独的构建和测试命令(它们一个接一个地运行)。

这是我的特定于测试的 webpack 配置(例如 webpack.config.babel.test.js):

import webpack from 'webpack';
import { join, resolve, parse } from 'path';
import SplitByPathPlugin from 'webpack-split-by-path';
import file from 'file';

const plugins = [
  new SplitByPathPlugin([
    {
      name: 'vendor',
      path: resolve(__dirname, 'node_modules')
    }
  ]),

  new webpack.SourceMapDevToolPlugin({
    test: /\.jsx?$/,
    exclude: [/vendor/]
  })
];

const entryPoints = {};
const testFileRegex = new RegExp('\.test\.jsx?$');
const pathPrefixRegex = new RegExp('^src/js/?');

file.walkSync('src/js/', (dirPath, dirs, files) => {
  for (const file of files) {
    if (file.match(testFileRegex)) {
      const parsedPath = parse(file);
      const entryKey = join(
        dirPath.replace(pathPrefixRegex, ''),
        parsedPath.name
      );
      entryPoints[entryKey] = './' + join(dirPath, parsedPath.name);
    }
  }
});

const config = {
  entry: entryPoints,
  output: {
    filename: '/[name]-[chunkhash].js',
    chunkFilename: '/[name]-[chunkhash].js',
    path: resolve(__dirname, 'dist-test'),
    pathinfo: true
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader!eslint-loader',
        exclude: [/node_modules/],
      },
      {
        test: /\.json$/, loader: 'json'
      }
    ],
  },
  bail: true,
  resolve: {
    extensions: ['', '.js', '.jsx', '.json'],
  },
  plugins: plugins,
  stats: {
    assets: false,
    cached: false,
    children: false,
    chunks: false,
    chunkModules: false,
    chunkOrigins: false,
    hash: false,
    modules: false,
    publicPath: false,
    reasons: false,
    source: false,
    timings: false,
    version: false,
    warnings: false
  },
  node: {
    child_process: 'empty',
    fs: 'empty'
  },
  externals: {
    'react/addons': true,
    'react/lib/ExecutionEnvironment': true,
    'react/lib/ReactContext': 'window'
  }
};

export default config;

关键部分是它为每个测试文件创建一个入口点,并webpack-split-by-path在生成块时使用插件自动将应用程序与供应商代码分开。

这是我使用的业力配置:

process.env.BABEL_ENV = 'test';

function karmaConfig(config) {
  config.set({
    basePath: '',
    frameworks: ['mocha'],
    files: [
      {
        pattern: 'dist-test/vendor-*.js',
        watched: false
      },
      'dist-test/**/*.test-*js?(x)'
    ],
    exclude: [],
    reporters: ['progress'],
    port: 9876,
    colors: true,
    browsers: ['Firefox', 'Chrome'],
    singleRun: true,
    logLevel: config.LOG_ERROR
  })
}

export default karmaConfig;

关键部分是供应商文件在files配置选项中首先列出并设置为不被监视,然后是测试文件。这确保了供应商代码总是首先为每个测试用例加载/插入。

我的问题是问是否有另一种方法,但这种方法效果很好。性能要好得多。

编辑 1

这种方法的唯一缺点(一开始我没有意识到)是你不能真正实现测试观察,因为你可以使用karma-webpack和预处理(通过 webpack),因为构建和测试的解耦脚步。

编辑 2

这种方法会遇到每次更改应用程序代码时重新编译供应商代码的问题(即使您没有添加/删除任何供应商库)。这让事情变得多余。

您想要解决此问题并能够再次开始测试观看是这样的:

  1. dist-test/在监视模式下运行 Webpack,以便在应用程序代码更改时构建到您的目录中。
  2. 以监视模式运行 Karma,指向目录中正在更新的所有测试文件dist-test/

这个解决方案是完美的,除了一个缺点,你不能在一个 npm/yarn 命令中运行这两个东西。

注意:Webpack 测试构建的输出文件名不应包含任何哈希(即文件名应在其内容更改之间保持一致)。这样当您更改测试文件时,您不会运行旧的和新的测试代码(因为 Webpack 不会删除旧文件)。.

于 2016-12-21T08:41:34.843 回答