获取 WebStorm + Karma + Webpack 以加载 jQuery 用于 AngularJs 指令单元测试

Get WebStorm + Karma + Webpack to load jQuery for AngularJs Directive Unit Tests

注意: 这尤其会帮助 运行s karma.conf.js 通过 WebStorm 的人。

问题:

我试图 运行 对指令进行一些测试,但由于它不断返回,"TypeError: 'undefined' is not a function" 我开始缩小问题可能所在的范围。结果:它似乎在读取模板,但模板上的 div 好像是空的。

我的测试

describe("Main Component Directive", function() {
var $scope, $element, directiveTemplate;

beforeEach(angular.mock.module('app'))

beforeEach(inject(function ($rootScope, $compile) {
  $scope = $rootScope.$new();
  directiveTemplate = '<gk-directive></gk-directive>';
  $element = $compile(directiveTemplate)($scope);
  $scope.$digest();
}));

it("should show reset button when current time is <5s under session/breakLength", function() {
  var button = $element.find(".button")
  expect(button).toBeDefined();
  console.log(button.text())
});

测试通过,但不会 console.log 此模板中的文本: container.html

<div>
    <div class="button">Button Here</div>
</div>

我的指令会不会有问题..?

module.exports = angular.module('app')
  .directive('gkTimerDirective', function () {
    return {
      template: require('./container.html') //gets turned into a string by webpack's raw-loader
    }
  });

我一直在浏览 Whosebug 并且有很多测试不同类型的指令及其行为的示例,但似乎我在这里缺少一些基本的东西。我确实在 AngularJs 或 Angular-Mocks 之前添加了 jQuery。

我觉得我缺少一些基本的东西。如果我像我一样 console.log,我不应该得到 "Button Here",而不是两个单引号:" '' "?

更新

澄清一下,这里的关键问题是 AngularJs 在寻找 class 时没有使用 $element.find() 遍历 DOM,尽管jQuery 确实应该加载的事实。

我认为你的指令应该是

angular.module('app')
  .directive('gkTimerDirective', function () {
    return {
      templateUrl: './container.html' //gets turned into a string by webpack's raw-loader
    }
  });

对发生的事情的解释

当我尝试 运行 使用 npm 运行 命令测试时,我注意到所有测试都通过了,但是当我 运行 通过 WebStorm 的 "Run karma.conf.js" 它表现得好像 jQuery 在 Angular 之前没有被加载,因此,它无法通过它的 class 找到 div,最后的测试,我在预加载 jQuery 的情况下使用 angular.element,继续失败。

我只能认为这是因为 jQuery 不容易被构建系统吸收。事实上,您可以看到 Webpack 在达到 jQuery 之后必须如何做一些额外的工作。

Hash: d234b2da503b21a23772
Version: webpack 1.12.9
Time: 395ms
                 Asset     Size  Chunks             Chunk Names
                  main  2.77 MB    0, 1  [emitted]  main
src/app.module.spec.js  2.77 MB    1, 0  [emitted]  src/app.module.spec.js
chunk    {0} main (main) 2.56 MB [rendered]
    [0] ./src/app.module.spec.js 273 bytes {0} {1}
    [1] ./src/jquery.js 1.38 MB {0} {1}
    [2] (webpack)/buildin/module.js 251 bytes {0} {1}
    [3] (webpack)/buildin/amd-options.js 43 bytes {0} {1}
    [4] ./src/app.module.js 2.42 kB {0} {1}
    [5] ./~/angular/index.js 48 bytes {0} {1}
    [6] ./~/angular/angular.js 1.07 MB {0} {1}
    [7] ./src/factories/index.js 1.03 kB {0} {1}
    [8] ./src/factories/timer.service.js 9.16 kB {0} {1}
    [9] ./src/timer/index.js 1.26 kB {0} {1}
   [10] ./src/timer/gkTimer.directive.js 1.82 kB {0} {1}
   [11] ./src/timer/gk-timer-container.html 144 bytes {0} {1}
   [12] ./src/timer/timerContainerCtrl.controller.js 4.12 kB {0} {1}
   [13] ./~/angular-mocks/angular-mocks.js 82.8 kB {0} {1}
   [14] ./src/tests/timer.service.spec.js 3.27 kB {0} {1}
   [15] ./src/tests/timer.spec.js 1.15 kB {0} {1} [built]

我仍然不确定为什么这是个问题,但它确实激发了解决方案。

解决方案

因为我只使用 jQuery 来测试指令,所以我只是将它添加到我在 Karma 上的文件列表中:

var path = require('path');    
var _ = require('lodash');
var here = require('path-here');

// SET-UP SETTINGS
process.env.NODE_ENV = process.env.NODE_ENV || 'test';

// coverage always true when testing (for me)
var coverage = true // = process.env.COVERAGE === 'true';

// ci determines if autowatch and single run will be true or false
var ci = process.env.NODE_ENV === 'test:ci';
if (coverage) {
  console.log('-- recording coverage --');
}

// all runs after the NODE_ENV has been set to 'test'
var webpackConfig = require('./webpack.config');
var entry = path.join(webpackConfig.context, webpackConfig.entry);
var preprocessors = {};
preprocessors[entry] = ['webpack'];

// SETTINGS INPUT

module.exports = function(config) {
  config.set({
    basePath: './',
    frameworks: ['jasmine'],
    files: [
      './node_modules/jquery/dist/jquery.js', // <-- Added it right here
      entry
    ],
    exclude: [],
    preprocessors: preprocessors,
    reporters: getReporters(),
    webpack: webpackConfig,
    webpackMiddleware: {noInfo: true},
    coverageReporter: {
      reporters: [
        {type: 'lcov', dir: 'coverage/', subdir: '.'},
        {type: 'json', dir: 'coverage/', subdir: '.'},
        {type: 'text-summary'}
      ]
    },
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: !ci,
    browsers: ['PhantomJS'],
    singleRun: ci,
    browserNoActivityTimeout: 180000,
    plugins: [
      'karma-webpack',
      'karma-jasmine',
      'karma-coverage',
      'karma-phantomjs-launcher'
    ]
  });
};

function getReporters() {
  var reps = ['progress'];
  if (coverage) {
    reps.push('coverage');
  }
  return reps;
}

现在,为了测试,首先加载 jQuery,然后 Angular 可以通过 class、id 或任何选择器 jQuery 搜索 DOM 元素允许。

但是对于生产呢?

我没有理由认为在我的情况下它可能不适用于生产构建,但如果这是你的问题,请尝试以下操作:https://github.com/webpack/webpack/issues/582