2016-02-15 89 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的問題。有沒有解決這個問題? –