Karma + Webpack (babel-loader) + ES6 "Unexpected token import"

Karma + Webpack (babel-loader) + ES6 "Unexpected token import"

/编辑:我将配置完全剥离到最低限度以证明问题所在。我还上传了一个工作项目到 GitHub,你可以签出,所以你可以自己看看。

GitHub 上的问题用例:webpack-angular15-es6-karma (download 7z archive)

npm install
npm run build
npm run test

我知道有几个相关的问题,但世界变化如此之快,因素/依赖性如此之多,我无法用当前提出的解决方案解决这个问题。

我有一个 webpack 配置可以处理我所有的源代码,而且效果很好。

为了测试,我重复使用该配置来处理加载源文件和测试文件的单个中央入口脚本。我找不到另一种方法将模块从我的源代码导入到我的测试代码中进行测试。

Karma重用我的webpack配置构建良好,但是浏览器一打开就报错

源代码使用 ES6 导入和 webpack require 语句。

package.json:

npm run build >>> webpack --config webpack.config.js --display-error-details --colors --progress

npm run test >>> karma start --single-run --no-auto-watch karma.config.js

{
  "name": "ProblemDemo",
  "scripts": {
    "build": "rimraf dist && webpack --config webpack.config.js --display-error-details --colors --progress",
    "test": "karma start --single-run --no-auto-watch karma.config.js"
  },
  "dependencies": {
    "angular": "^1.5.7",
    "angular-filter": "^0.5.8"
  },
  "devDependencies": {
      "webpack": "1.13.1",
      "html-loader": "0.4.3",
      "babel-loader": "5.3.2",
      "html-webpack-plugin": "1.6.1",
      "rimraf": "^2.5.3",
      "run-sequence": "1.1.2",
      "jasmine-core": "^2.4.1",
      "karma": "^0.13.19",
      "karma-chrome-launcher": "^0.2.2",
      "karma-coverage": "^0.5.3",
      "karma-jasmine": "^0.3.6",
      "karma-webpack": "^1.7.0",
      "loader-utils": "^0.2.12"
  }
}

karma.config.js:

module.exports = function (config) {
    config.set({
        browsers: ['Chrome'],
        coverageReporter: {
            reporters: [
                { type: 'html', subdir: 'html' },
                { type: 'lcovonly', subdir: '.' }
            ]
        },
        files: ['./tests.webpack.js'],
        frameworks: ['jasmine'],
        preprocessors: { './tests.webpack.js': ['webpack'] },
        reporters: ['progress', 'coverage'],
        webpack: configureWebpack()
    });

    function configureWebpack(webpackConfigFunction) {
        var webpackConfig = require('./webpack.config');
        webpackConfig.entry = undefined; // karma will pass the proper argument for entry
        return webpackConfig;
    }
};

如您所见,我没有使用 karma-babel 插件:我不确定为什么我需要这些插件,因为我已经有了一个可以使用 import / require 语句的代码构建。

test_entry.js:

var testsContext = require.context('./test', true, /\.js$/);
testsContext.keys().forEach(testsContext);

var srcContext = require.context('./app', true, /\.js$/);
srcContext.keys().forEach(srcContext);

webpack 构建顺利成功(并发出 test_entry.js 预期文件大小的块),但随后 Karma 打开 Chrome 并尽快页面已加载我收到以下错误:

Chrome 51.0.2704 (Windows 7 0.0.0) ERROR

Uncaught SyntaxError: Unexpected token import

at the_path/test_entry.js:41

test_entry.js 没有 41 行,也不包含 import 语句,无论如何它们都应该得到处理。怎么了?

如果你也想知道 webpack 配置:

// webpack.config.js, works perfectly for normal builds but not with Karma
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
 debug: true,
 entry: {
  app: ['./app/index.js'],
  vendor: ['./app/vendor.js']
 },
 output: {
  path: path.join(__dirname, 'dist'),
  filename: 'js/[name].js'
 },
 plugins: [
  new HtmlWebpackPlugin({
   template: './app/index.html',
   inject: 'body',
   minify: false
  }),
  new webpack.optimize.CommonsChunkPlugin('vendor', 'js/vendor.js'),
  new webpack.SourceMapDevToolPlugin({
   filename: '[file].map',
   exclude: /vendor/
  })
 ],
 resolve: {
  extensions: ['', '.js'],
  alias: {
   app: path.join(__dirname, 'app')
  }
 },
 module: {
  loaders: [
   {
    test: /\.js$/,
    loader: 'babel-loader',
    include: path.join(__dirname, 'app'),
    exclude: path.join(__dirname, 'node_modules')
   },
   {
    test: /\.html$/,
    loader: 'html-loader'
   }
  ]
 },
 resolveLoader: {
  root: path.join(__dirname, 'node_modules')
 },
};

如果你想看我的测试,test_entry.js,我无法到达 运行:

import jasmine from 'jasmine-core';
import readableNumberFilter from './file_path/readableNumber.filter';

// for some reason needed, or else unexpected token errors during build:
var describe = jasmine.describe;
var it = jasmine.it;
var expect = jasmine.expect;

describe('readableNumber Filter', function () {
 describe('readableNumber Filter formatting', () => {
  it('it should support optional arguments', function () {
   expect(readableNumberFilter("50.3")).toEqual("50,30");
  });
 });
});


编辑 20-7-2016

问题仍然存在于更新的 babel-loader 依赖项中(包括设置 es2015 预设选项)。 "babel-core": "^6.11.4", "babel-loader": "^6.2.4", "babel-preset-es2015": "^6.9.0",

问题是您没有转译测试源 - 文件 src/global/filters/dateFormat.filter.spec.js 没有转译。

您需要更改此加载程序配置:

{
    test: /\.js$/,
    loader: 'babel-loader',
    include: path.join(__dirname, 'app'),
    exclude: path.join(__dirname, 'node_modules')
},

如下所示,使其工作:

{
    test: /\.js$/,
    loader: 'babel-loader',
    include: [
        path.join(__dirname, 'app'),
        path.join(__dirname, 'test')
    ],
    exclude: path.join(__dirname, 'node_modules')
},

webpack.optimize.CommonsChunkPlugin 插件也有问题 - 它应该因业力而被禁用: https://github.com/webpack/karma-webpack/issues/22

禁用此插件后,您的测试文件出现错误:

import jasmine from 'jasmine-core';

import readableNumberFilter from 'readableNumber.filter';

var describe = jasmine.describe;
var it = jasmine.it;
var expect = jasmine.expect;

describe('readableNumber Filter', function () {
    describe('readableNumber Filter formatting', () => {
        it('it should support optional arguments', function () {
            expect(readableNumberFilter("50.3")).toEqual("50,30");
        });
    });
});

本次测试错误较少:

  1. import jasmine from 'jasmine-core'; - 你不应该那样做(业力会做,它还会添加 describeitexpect
  2. import readableNumberFilter from 'readableNumber.filter'; - 这不是实例化 angular 服务以测试它们的方式。

你应该做这样的事情(这个测试实际上适用于上面提到的所有修复):

import angular from 'angular';
import 'angular-mocks';

import testModule from '../../../../app/src/global/index';

const { module, inject } = angular.mock;

describe('readableNumber Filter', () => {
    beforeEach(module(testModule));

    let $filter;

    beforeEach(inject((_$filter_) => {
        $filter = _$filter_;
    }));

    describe('readableNumber Filter formatting', () => {
        it('it should support optional arguments', () => {
            const result = $filter('readableNumber')("50.3");
            expect(result).toEqual("50,30");
        });
    });
});

注意:您需要安装模块angular-mocks


为了支持代码覆盖率报告,您需要配置测试 webpack 配置以使用类似 babel-istanbul-loader 的东西。顺便说一句,你还需要升级到 Babel6。

此外,您还需要使 webpack 配置更具可配置性(测试和生产的配置需要略有不同)。

我已向您发送了包含所有这些修复程序的拉取请求:https://github.com/bbottema/webpack-angular15-es6-karma/pull/1


关于使用 webpack 构建 angular 1.x 项目,包括通过 karma 进行代码覆盖率测试 - 也许您会对我的项目感兴趣:https://github.com/zxbodya/angular-webpack-seed - 它是包含所有内容的入门模板所需配置。