2016-02-15 93 views
9

我正在构建一个使用Angular 2,SystemJS和Karma进行测试的Web应用程序。用SystemJS和Karma在Angular 2中加载节点模块

我试图加载节点模块ngrx/store在测试:

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... 
    }); 
}); 

但是,我的测试中失败,出现以下消息:

404: /@ngrx/store 
Chrome 48.0.2564 (Mac OS X 10.11.3) ERROR 
    Error: XHR error (404 Not Found) loading http://localhost:9876/@ngrx/store 

其实我有在开发中同样的问题而且事实证明,SystemJS不知道在哪里可以找到@ngrx/store。为了解决这个问题,我做了这个:

System.config({ 
    packages: { 
    src: { 
     format: 'register', 
     defaultExtension: 'js' 
    } 
    }, 
    map: { '@ngrx/store' : 'node_modules/@ngrx/store/dist/store.js' } // <-- this 
}); 

我修改了我的Karma填充文件来做同样的事情。一旦运行测试的第二次,我现在得到一个不同的错误:

404: /node_modules/@ngrx/store/dist/store.js 
Chrome 48.0.2564 (Mac OS X 10.11.3) ERROR 
    Error: XHR error (404 Not Found) loading http://localhost:9876/node_modules/@ngrx/store/dist/store.js 

这意味着它必须服用我给它考虑了明确的路径,但它仍然无法找到该模块。然而,这是模块的正确路径,并且在浏览器中加载时工作正常。

我很遗憾接下来要做什么。有人能指引我朝着正确的方向吗?

有几件事情需要注意:

  • 添加节点模块噶的files阵列是不是一种选择,因为它的依赖需要与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); 
    }); 
} 

更新

有一个例子库与错误here。您可以看到导致错误here的具体更改。运行$ npm install$ npm test以获取错误。

+0

从测试时,我面临着类似的问题浏览器。路径似乎是这里的问题。有关此问题的任何更新或解决了您的问题? – Gary

+0

尚未解决。考虑开设赏金。我需要解决这个问题。 – weltschmerz

+0

你可以上传[mcve](http://stackoverflow.com/help/mcve)作为git回购吗? –

回答

7

包括@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'); 
.... 

这将导致一个错误:

Uncaught ReferenceError: require is not defined

// 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} 

这将基本列出它在window.__karma__.files对象中,但不会将其作为业务中的脚本添加到context.html - 浏览器不会加载并运行导致错误的代码。装载应该由SystemJS来处理...

如果您使用singleRun: false运行karma测试,您可以检查Chrome的Devtools> Network中的文件。你会看到那里的加载文件的列表,而这也正是拼图的最后一块是:

在你karma-test-shim.js变化System.config.map到:

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

Executed 4 of 4 SUCCESS (0.037 secs/0.008 secs)

+0

不错。谢谢。 – weltschmerz

+0

所以你必须从'files'中删除这个模式,并将'map'添加到System.config中? –

+0

@mithun_daa你必须在'files []'中保持模式,否则当SystemJS尝试加载它时文件将不会被提供。你只需要设置'include:false',这样它就不会被浏览器加载和执行,并且将加载保留到SystemJS中。 – Sasxa

0

发送了修复程序的PR。有可能是一个更好的方式来做到这一点,但这个工程:

复制store.js文件到dist文件夹通过更新package.jsonbuild脚本

... && cp node_modules/@ngrx/store/dist/store.js dist/store.js 

更新在karma-test.shim.js

paths: { '@ngrx/store' : '/base/dist/store.js' } 
路径
+2

感谢您的公关,但这是行不通的。它和移动包装本质上是一样的。如果更多软件包发生这种情况,它也不会扩展。我想了解为什么SystemJS无法加载模块并找到解决方案。 – weltschmerz

+0

我也遇到了pathing,Karma和SystemJS的问题。有没有解决这个问题? –