在Angular 2中使用SystemJS和Karma加载节点模块

在Angular 2中使用SystemJS和Karma加载节点模块,angular,karma-runner,systemjs,Angular,Karma Runner,Systemjs,我正在使用Angular 2、SystemJS和Karma for tests构建一个web应用程序 我正在尝试在测试中加载节点模块: import { it, describe, expect, beforeEach, inject } from 'angular2/testing'; import { Store } from '@ngrx/store'; describe('Graphs store', () => { let graphs; beforeEach(

我正在使用Angular 2、SystemJS和Karma for tests构建一个web应用程序

我正在尝试在测试中加载节点模块:

import {
  it, describe, expect, beforeEach, inject
} from 'angular2/testing';

import { Store } from '@ngrx/store';

describe('Graphs store', () => {
  let graphs;

  beforeEach(inject([Store], (store: Store<any>) => {
    graphs = store.select('graphs');
  }));

  it('works', () => {
    // expect graphs to do something...
  });
});
实际上,我在dev中也遇到了同样的问题,结果是SystemJS不知道在哪里可以找到
@ngrx/store
。为了解决这个问题,我做了以下工作:

System.config({
  packages: {
    src: {
      format: 'register',
      defaultExtension: 'js'
    }
  },
  map: { '@ngrx/store' : 'node_modules/@ngrx/store/dist/store.js' } // <-- this
});
这意味着它必须考虑我给它的显式路径,但它仍然找不到模块。但是,它是模块的正确路径,在浏览器中加载时可以工作

我不知道下一步该怎么办。有人能给我指出正确的方向吗

需要注意的几点:

  • 将节点模块添加到Karma的
    文件
    数组中不是一个选项,因为它的依赖关系需要用SystemJS解决
  • 这只会发生在SystemJS需要自定义说明其所在位置的节点模块上。只要SystemJS能够找到,我就可以在测试中加载其他模块,而无需提供特定的位置
这是我的业力配置:

// Set up with the help of
// http://twofuckingdevelopers.com/2016/01/testing-angular-2-with-karma-and-jasmine/

module.exports = function(config) {
  config.set({

    basePath: '.',

    frameworks: ['jasmine'],

    files: [
      // paths loaded by Karma
      {pattern: 'node_modules/angular2/bundles/angular2-polyfills.js', included: true, watched: true},
      {pattern: 'node_modules/systemjs/dist/system.src.js', included: true, watched: true},
      {pattern: 'node_modules/rxjs/bundles/Rx.js', included: true, watched: true},
      {pattern: 'node_modules/angular2/bundles/angular2.dev.js', included: true, watched: true},
      {pattern: 'node_modules/angular2/bundles/testing.dev.js', included: true, watched: true},
      {pattern: 'karma-test-shim.js', included: true, watched: true},

      // paths loaded via module imports
      {pattern: 'src/**/*.js', included: false, watched: true},

      // paths to support debugging with source maps in dev tools
      {pattern: 'src/**/*.ts', included: false, watched: false},
      {pattern: 'src/**/*.js.map', included: false, watched: false}
    ],

    // proxied base paths
    proxies: {
      // required for component assets fetched by Angular's compiler
      '/src/': '/base/src/'
    },

    port: 9876,

    logLevel: config.LOG_INFO,

    colors: true,

    autoWatch: true,

    browsers: ['Chrome'],

    // Karma plugins loaded
    plugins: [
      'karma-jasmine',
      'karma-coverage',
      'karma-chrome-launcher'
    ],

    // // Coverage reporter generates the coverage
    // reporters: ['progress', 'dots', 'coverage'],
    //
    // // Source files that you wanna generate coverage for.
    // // Do not include tests or libraries (these files will be instrumented by Istanbul)
    // preprocessors: {
    //   'src/**/!(*spec).js': ['coverage']
    // },

    // coverageReporter: {
    //   reporters:[
    //     {type: 'json', subdir: '.', file: 'coverage-final.json'}
    //   ]
    // },

    singleRun: true
  })
};
这是我的因果报应:

// Tun on full stack traces in errors to help debugging
Error.stackTraceLimit = Infinity;

jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;

// // Cancel Karma's synchronous start,
// // we will call `__karma__.start()` later, once all the specs are loaded.
__karma__.loaded = function() {};

System.config({
  packages: {
    'base/src': {
      defaultExtension: 'js',
      format: 'register',
      map: Object.keys(window.__karma__.files).filter(onlyAppFiles).reduce(createPathRecords, {})
    }
  },
  // This makes it work in the browser, but not in my tests!
  paths: { '@ngrx/store' : 'node_modules/@ngrx/store/dist/store.js' }
});

System.import('angular2/src/platform/browser/browser_adapter')
  .then(function(browser_adapter) { browser_adapter.BrowserDomAdapter.makeCurrent(); })
  .then(function() { return Promise.all(resolveTestFiles()); })
  .then(function() { __karma__.start(); }, function(error) { __karma__.error(error.stack || error); });

function createPathRecords(pathsMapping, appPath) {
  // creates local module name mapping to global path with karma's fingerprint in path, e.g.:
  // './vg-player/vg-player':
  // '/base/src/vg-player/vg-player.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
  var pathParts = appPath.split('/');
  var moduleName = './' + pathParts.slice(Math.max(pathParts.length - 2, 1)).join('/');
  moduleName = moduleName.replace(/\.js$/, '');
  pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath];
  return pathsMapping;
}

function onlyAppFiles(filePath) {
  return /\/base\/src\/(?!.*\.spec\.js$).*\.js$/.test(filePath);
}

function onlySpecFiles(path) {
  return /\.spec\.js$/.test(path);
}

function resolveTestFiles() {
  return Object.keys(window.__karma__.files)  // All files served by Karma.
    .filter(onlySpecFiles)
    .map(function(moduleName) {
      // loads all spec files via their global module names (e.g.
      // 'base/src/vg-player/vg-player.spec')
      return System.import(moduleName);
    });
}
更新
有一个示例存储库存在此错误。您可以看到导致错误的特定更改。运行
$npm install
$npm test
以获取错误。

发送了带有修复程序的PR。也许有更好的方法可以做到这一点,但这是可行的:

通过更新
package.json
build
脚本,将
store.js
文件复制到
dist
文件夹

... && cp node_modules/@ngrx/store/dist/store.js dist/store.js
更新
karma test.shim.js中的路径

paths: { '@ngrx/store' : '/base/dist/store.js' }

@ngrx/store
与其他捆绑包一起使用,可以解决404错误

    // for testing in karma.conf.js
    files: [
        // paths loaded by Karma
        {pattern: 'node_modules/@ngrx/store/dist/store.js', included: true, watched: true},
    ],
但与编译为系统模块的其余捆绑包不同,
@ngrx/store
编译为commonjs模块

// 'node_modules/angular2/bundles/angular2.dev.js'
"format register";
System.register("angular2/src/facade/lang", [], true, function(require, exports, module) {
....

// 'node_modules/rxjs/bundles/Rx.js'
"format register";
System.register("rxjs/util/root", [], true, function(require, exports, module) {
....

// 'node_modules/@ngrx/store/dist/store.js'
....
var Observable_1 = require('rxjs/Observable');
....
这会导致错误:

未捕获引用错误:未定义require

这将基本上在
窗口中列出它。uuuu karma\uuuu.files
对象,但不会将其作为脚本添加到karma的
上下文中。html
-浏览器不会加载并运行导致错误的代码。加载应由SystemJS处理

如果您使用
singleRun:false
运行karma测试,您可以在Chrome的Devtools>网络中检查文件。您将看到加载文件的列表,这就是拼图的最后一部分:

在您的
karma test shim.js
中,将
System.config.map
更改为:

map: { '@ngrx/store' : '/base/node_modules/@ngrx/store/dist/store.js' }
成功执行4次中的4次(0.037秒/0.008秒)


在从浏览器进行测试时,我也面临类似的问题。路径似乎是这里的问题。是否对此进行了更新,或者您的问题是否已解决?尚未解决。考虑开一个悬赏。我需要解决这个问题。你能上传一个git回购吗?@arturgrzesiak给你:。我所做的导致错误出现的更改如下:运行
npm install
npm test
以重现错误。它将出现在终端上,应该说“404,找不到@ngrx/store module”。如果您不删除该存储库,它将非常有用。感谢PR,但这不会起作用。这基本上与移动包裹是一样的。如果更多的包出现这种情况,它也不会扩展。我想了解为什么SystemJS无法加载模块并找到解决方案。我还遇到了路径、Karma和SystemJS方面的问题。这有什么解决办法吗?那么您是否必须从
文件中删除模式,并将
映射添加到System.config中?@mithun_daa您必须将模式保留在
文件[]
,否则当SystemJS尝试加载它时,将无法提供该文件。您只需设置
include:false
,使其不被浏览器加载和执行,并将加载留给SystemJS。@Sasxa Ah!!谢谢你澄清这一点。我错过了
include:false
。干杯
// 'node_modules/angular2/bundles/angular2.dev.js'
"format register";
System.register("angular2/src/facade/lang", [], true, function(require, exports, module) {
....

// 'node_modules/rxjs/bundles/Rx.js'
"format register";
System.register("rxjs/util/root", [], true, function(require, exports, module) {
....

// 'node_modules/@ngrx/store/dist/store.js'
....
var Observable_1 = require('rxjs/Observable');
....
// with {pattern: '~/store.js', indluded: true}
// context.html includes
<script type="text/javascript" src="/base/node_modules/@ngrx/store/dist/store.js?fb5e807149603c3c2f998c98faf6826c7e301d71"></script>
{pattern: 'node_modules/@ngrx/store/dist/store.js', included: false, watched: true}
map: { '@ngrx/store' : '/base/node_modules/@ngrx/store/dist/store.js' }