简体   繁体   中英

“System is not defined” in node module when running Karma tests of Angular 2 app

When I run "npm run test" I used to get all my unit tests running. Now, after adding a node module for a library I need to use (it's called Wijmo), I'm getting the following error in the console, which appears to be preventing all my unit tests from executing (instead, the Karma browser comes up green with no tests run).

It should be noted that the node module loads and runs with no issue in the app itself when using "npm start."

Here's the error:

Chrome 57.0.2987 (Windows 7 0.0.0) ERROR
  Uncaught ReferenceError: System is not defined
  at node_modules/wijmo/wijmo.js:13

Chrome 57.0.2987 (Windows 7 0.0.0) ERROR
  Uncaught ReferenceError: System is not defined
  at node_modules/wijmo/wijmo.js:13

Am I forgetting to add this module in a config somewhere? Or maybe it's a problem with the actual node module?

karma.config.js:

// #docregion
module.exports = function(config) {

    var appBase    = 'app/';       // transpiled app JS and map files
    var appSrcBase = 'app/';       // app source TS files
    var appAssets  = '/base/app/'; // component assets fetched by Angular's compiler

    var testingBase    = 'testing/';       // transpiled test JS and map files
    var testingSrcBase = 'testing/';       // test source TS files

    config.set({
        basePath: '',
        frameworks: ['jasmine'],
        plugins: [
            require('karma-jasmine'),
            require('karma-chrome-launcher'),
            require('karma-jasmine-html-reporter'), // click "Debug" in browser to see it
            require('karma-htmlfile-reporter') // crashing w/ strange socket error
        ],

        client: {
            builtPaths: [appBase, testingBase], // add more spec base paths as needed
            clearContext: false // leave Jasmine Spec Runner output visible in browser
        },

        customLaunchers: {
            // From the CLI. Not used here but interesting
            // chrome setup for travis CI using chromium
            Chrome_travis_ci: {
                base: 'Chrome',
                flags: ['--no-sandbox']
            }
        },
        files: [
            'node_modules/lodash/lodash.js',
            'node_modules/wijmo/wijmo.js',
            'node_modules/wijmo/wijmo.chart.js',
            'node_modules/wijmo/wijmo.chart.interaction.js',
            // System.js for module loading
            'node_modules/systemjs/dist/system.src.js',

            // Polyfills
            'node_modules/core-js/client/shim.js',
            'node_modules/reflect-metadata/Reflect.js',

            // zone.js
            'node_modules/zone.js/dist/zone.js',
            'node_modules/zone.js/dist/long-stack-trace-zone.js',
            'node_modules/zone.js/dist/proxy.js',
            'node_modules/zone.js/dist/sync-test.js',
            'node_modules/zone.js/dist/jasmine-patch.js',
            'node_modules/zone.js/dist/async-test.js',
            'node_modules/zone.js/dist/fake-async-test.js',

            // RxJs
            { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
            { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },

            // Paths loaded via module imports:
            // Angular itself
            { pattern: 'node_modules/@angular/**/*.js', included: false, watched: false },
            { pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false },

            { pattern: 'systemjs.config.js', included: false, watched: false },
            { pattern: 'systemjs.config.extras.js', included: false, watched: false },
            'karma-test-shim.js', // optionally extend SystemJS mapping e.g., with barrels

            // transpiled application & spec code paths loaded via module imports
            { pattern: appBase + '**/*.js', included: false, watched: true },
            { pattern: testingBase + '**/*.js', included: false, watched: true },


            // Asset (HTML & CSS) paths loaded via Angular's component compiler
            // (these paths need to be rewritten, see proxies section)
            { pattern: appBase + '**/*.html', included: false, watched: true },
            { pattern: appBase + '**/*.css', included: false, watched: true },

            // Paths for debugging with source maps in dev tools
            { pattern: appSrcBase + '**/*.ts', included: false, watched: false },
            { pattern: appBase + '**/*.js.map', included: false, watched: false },
            { pattern: testingSrcBase + '**/*.ts', included: false, watched: false },
            { pattern: testingBase + '**/*.js.map', included: false, watched: false}
        ],

        // Proxied base paths for loading assets
        proxies: {
            // required for component assets fetched by Angular's compiler
            "/app/": appAssets
        },

        exclude: [],
        preprocessors: {},
        // disabled HtmlReporter; suddenly crashing w/ strange socket error
        reporters: ['progress', 'kjhtml'],//'html'],

        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browsers: ['Chrome'],
        singleRun: false
    })
}

karma-test-shim.js:

// /*global jasmine, __karma__, window*/
Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing.

// Uncomment to get full stacktrace output. Sometimes helpful, usually not.
// Error.stackTraceLimit = Infinity; //

jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;

// builtPaths: root paths for output ("built") files
// get from karma.config.js, then prefix with '/base/' (default is 'app/')
var builtPaths = (__karma__.config.builtPaths || ['app/'])
    .map(function(p) { return '/base/'+p;});

__karma__.loaded = function () { };

function isJsFile(path) {
    return path.slice(-3) == '.js';
}

function isSpecFile(path) {
    return /\.spec\.(.*\.)?js$/.test(path);
}

// Is a "built" file if is JavaScript file in one of the "built" folders
function isBuiltFile(path) {
    return isJsFile(path) &&
        builtPaths.reduce(function(keep, bp) {
            return keep || (path.substr(0, bp.length) === bp);
        }, false);
}

var allSpecFiles = Object.keys(window.__karma__.files)
    .filter(isSpecFile)
    .filter(isBuiltFile);

System.config({
    baseURL: 'base',  // was originally /base... if ng2-translate messes up, try going back to that
    // Extend usual application package list with test folder
    packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } },

    // Assume npm: is set in `paths` in systemjs.config
    // Map the angular testing umd bundles
    map: {
        '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
        '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
        '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
        '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
        '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
        '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
        '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
        '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
        'ng2-translate': '/base/node_modules/ng2-translate'
    }
});

System.import('systemjs.config.js')
    .then(importSystemJsExtras)
    .then(initTestBed)
    .then(initTesting);

/** Optional SystemJS configuration extras. Keep going w/o it */
function importSystemJsExtras(){
    return System.import('systemjs.config.extras.js')
        .catch(function(reason) {
            console.log(
                'Warning: System.import could not load the optional "systemjs.config.extras.js". Did you omit it by accident? Continuing without it.'
            );
            console.log(reason);
        });
}

function initTestBed(){
    return Promise.all([
        System.import('@angular/core/testing'),
        System.import('@angular/platform-browser-dynamic/testing')
    ])

        .then(function (providers) {
            var coreTesting    = providers[0];
            var browserTesting = providers[1];

            coreTesting.TestBed.initTestEnvironment(
                browserTesting.BrowserDynamicTestingModule,
                browserTesting.platformBrowserDynamicTesting());
        })
}

// Import all spec files and start karma
function initTesting () {
    return Promise.all(
        allSpecFiles.map(function (moduleName) {
            return System.import(moduleName);
        })
    )
        .then(__karma__.start, __karma__.error);
}

package.json, just in case:

{
  "name": "app",
  "version": "1.0.1",
  "scripts": {
    "start": "tsc && concurrently \"tsc -w\" \"lite-server\" \"npm run generate-css\" \"npm run watch-css\" ",
    "pree2e": "npm run webdriver:update",
    "e2e": "tsc && concurrently \"http-server -s\" \"protractor protractor.config.js\" --kill-others --success first",
    "lint": "tslint ./app/**/*.ts -t verbose",
    "generate-css": "node-sass -r app --output ./generated-css",
    "watch-css": "node-sass -w -r app --output ./generated-css",
    "lite": "lite-server",
    "test": "tsc && concurrently \"tsc -w\" \"karma start karma.conf.js\"",
    "test-once": "tsc && karma start karma.conf.js --single-run",
    "tsc": "tsc",
    "tsc:w": "tsc -w"
  },
  "license": "",
  "author": "me",
  "dependencies": {
    "@angular/animations": "4.0.2",
    "@angular/common": "4.0.2",
    "@angular/compiler": "4.0.2",
    "@angular/compiler-cli": "4.0.2",
    "@angular/core": "4.0.2",
    "@angular/forms": "4.0.2",
    "@angular/material": "^2.0.0-beta.3",
    "@angular/http": "4.0.2",
    "@angular/platform-browser": "4.0.2",
    "@angular/platform-browser-dynamic": "4.0.2",
    "@angular/platform-server": "4.0.2",
    "@angular/router": "4.0.2",
    "angular-in-memory-web-api": "0.2.4",
    "angular2-ui-switch": "1.2.0",
    "bootstrap": "3.3.7",
    "core-js": "2.4.1",
    "mydatepicker":"1.2.9",
    "ng2-translate": "5.0.0",
    "reflect-metadata": "0.1.9",
    "rxjs": "5.0.1",
    "socket.io": "1.7.2",
    "lodash": "4.17.4",
    "socket.io-client": "1.7.2",
    "systemjs": "0.19.40",
    "wijmo": "wijmo-system-min",
    "zone.js": "0.8.5",
    "typescript": "2.2.2"
  },
  "devDependencies": {
    "@types/core-js": "0.9.35",
    "@types/jasmine": "2.5.40",
    "@types/node": "6.0.58",
    "@types/selenium-webdriver": "2.53.39",
    "@types/lodash": "4.14.62",
    "canonical-path":"0.0.2",
    "codelyzer": "0.0.25",
    "concurrently": "3.1.0",
    "http-server": "0.9.0",
    "jasmine-core": "2.5.2",
    "karma": "1.3.0",
    "karma-chrome-launcher": "2.0.0",
    "karma-cli": "1.0.1",
    "karma-htmlfile-reporter": "0.3.4",
    "karma-jasmine": "1.1.0",
    "karma-jasmine-html-reporter": "0.2.2",
    "lite-server": "2.2.2",
    "live-server": "1.1.0",
    "lodash": "4.17.4",
    "node-sass": "3.13.1",
    "nodemon": "1.11.0",
    "protractor": "3.3.0",
    "rimraf": "2.5.4",
    "tslint": "3.15.1"
  }
}

systemjs.config.js

(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': 'node_modules/'
        },
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            app: 'app',
            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

            // other libraries
            'rxjs':                      'npm:rxjs',
            'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
            'ng2-translate':             'npm:ng2-translate/bundles',
            'lodash':                    'npm:lodash',
            'socket.io-client':          'npm:socket.io-client/socket.io.js',
            'mydatepicker':              'npm:mydatepicker',
            'wijmo':                     'npm:wijmo',
            'angular2-ui-switch':        'npm:angular2-ui-switch'
        },
        // packages tells the System loader how to load when no filename and/or no extension
        packages: {
            app: {
                main: './main.js',
                defaultExtension: 'js'
            },
            rxjs: {
                defaultExtension: 'js'
            },
            'ng2-translate': {
                main: 'ng2-translate',
                defaultExtension: 'umd.js'
            },
            'socket.io-client': {
                defaultExtension: 'js'
            },
            'mydatepicker': {
                main: './dist/index.js',
                defaultExtension: 'js'
            },
            'angular2-ui-switch': {
                main: './dist/index.js',
                defaultExtension: 'js'
            },
            lodash: {
                main: './lodash.js',
                defaultExtension: 'js'
            },
            wijmo: {
                main: './wijmo.js',
                defaultExtension: 'js'
            }
        }
    });
})(this);

I eventually got this problem to go away by updating the .html document where I define which tests show up in the karma report. I'm pretty sure the problem was simply that I wasn't referencing the spec file in this document. Since the spec file was getting picked up by karma's detection via its regular expressions, it was trying to run the tests, but when it wasn't defined in the .html it was throwing the error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM