Issue getting TypeScript, Karma, RequireJS and Cha

2019-05-18 22:04发布

问题:

I'm trying to rewrite one of my projects using TypeScript and because I'm quite new to TypeScript and RequireJS I'm not sure what I'm missing.

I've followed this guide Karma - RequireJS and double checked everything, yet I haven't managed to get it working at least not RequireJS.

P.S. The error I'm getting is at the end of the post.

The directory structure I'm using for this project is as follow:

.
|-- WebEssentials-Settings.json
|-- build
|-- jake.sh
|-- jakefile.js
|-- node_modules
|   |-- chai
|   |   |-- CONTRIBUTING.md
|   |   |-- History.md
|   |   |-- README.md
|   |   |-- ReleaseNotes.md
|   |   |-- bower.json
|   |   |-- chai.js
|   |   |-- index.js
|   |   |-- karma.conf.js
|   |   |-- karma.sauce.js
|   |   |-- lib
|   |   |-- node_modules
|   |   |-- package.json
|   |   `-- sauce.browsers.js
|   |-- jake
|   |   |-- Jakefile
|   |   |-- Makefile
|   |   |-- README.md
|   |   |-- bin
|   |   |-- lib
|   |   |-- node_modules
|   |   |-- package.json
|   |   `-- test
|   |-- karma
|   |   |-- CHANGELOG.md
|   |   |-- LICENSE
|   |   |-- README.md
|   |   |-- bin
|   |   |-- config.tpl.coffee
|   |   |-- config.tpl.js
|   |   |-- config.tpl.ls
|   |   |-- karma-completion.sh
|   |   |-- lib
|   |   |-- node_modules
|   |   |-- package.json
|   |   |-- requirejs.config.tpl.coffee
|   |   |-- requirejs.config.tpl.js
|   |   `-- static
|   |-- karma-chai
|   |   |-- LICENSE
|   |   |-- README.md
|   |   |-- adapter.js
|   |   |-- index.js
|   |   `-- package.json
|   |-- karma-mocha
|   |   |-- LICENSE
|   |   |-- README.md
|   |   |-- lib
|   |   `-- package.json
|   |-- karma-requirejs
|   |   |-- LICENSE
|   |   |-- README.md
|   |   |-- lib
|   |   `-- package.json
|   |-- mocha
|   |   |-- Readme.md
|   |   |-- bin
|   |   |-- images
|   |   |-- index.js
|   |   |-- lib
|   |   |-- mocha.css
|   |   |-- mocha.js
|   |   |-- node_modules
|   |   `-- package.json
|   |-- requirejs
|   |   |-- README.md
|   |   |-- bin
|   |   |-- package.json
|   |   `-- require.js
|   `-- shelljs
|       |-- LICENSE
|       |-- README.md
|       |-- bin
|       |-- global.js
|       |-- make.js
|       |-- package.json
|       |-- scripts
|       |-- shell.js
|       `-- src
|-- scratchpad.txt
|-- src
|   |-- app.main.js
|   |-- app.main.js.map
|   |-- app.main.ts
|   |-- core
|   |   |-- exceptions.js
|   |   |-- exceptions.js.map
|   |   |-- exceptions.ts
|   |   |-- string.js
|   |   |-- string.js.map
|   |   |-- string.ts
|   |   |-- types.js
|   |   |-- types.js.map
|   |   `-- types.ts
|   |-- css
|   |-- index.html
|   |-- libs
|   |   |-- jquery-2.1.0.js
|   |   |-- require.js
|   |   `-- typings
|   |-- tests
|   |   |-- core
|   |   |-- test.main.js
|   |   |-- test.main.js.map
|   |   `-- test.main.ts
|   |-- tsToolkit.csproj
|   |-- tsToolkit.csproj.user
|   |-- web.Debug.config
|   |-- web.Release.config
|   |-- web.config
|   `-- widgets
|-- tools
|   |-- karma
|   |   `-- karma.conf.js
|   |-- lint
|   |   `-- lint_runner.js
|   `-- mocha
|       `-- mocha.ext.js
|-- tsToolkit.sln
|-- tsToolkit.sln.DotSettings.user
`-- tsToolkit.v12.suo

43 directories, 83 files

Here is the configuration file I'm using for Karma. -- karma.conf.js

// Karma configuration
// Generated on Wed Sep 25 2013 00:47:38 GMT+0300 (Jerusalem Daylight Time)

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

    // base path, that will be used to resolve files and exclude
    basePath: '../../',


    // frameworks to use
    frameworks: ['requirejs', 'mocha', 'chai'],


    // list of files / patterns to load in the browser
    files: [
        "tools/mocha/mocha.ext.js",
        "src/libs/*.js",
        "src/tests/*/*.js",
        "src/tests/test.main.js"
    ],


    // list of files to exclude
    exclude: [
        'src/main.js'
    ],


    // test results reporter to use
    // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
    reporters: ['progress'],


    // web server port
    port: 8380,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: [],


    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 60000,


    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};

Here is the configuration I have for RequireJS - tests.main.js

interface Window {
// ReSharper disable InconsistentNaming
    __karma__: any;
// ReSharper restore InconsistentNaming
}

var tests = [];
for (var file in window.__karma__.files) {
    if (window.__karma__.files.hasOwnProperty(file)) {
        if (/\.tests\.js$/.test(file))
        {
            tests.push(file);
        }
    }
}

declare var requirejs: any;
requirejs.config({
    baseUrl: '/base/src',

    deps: tests,

    callback: window.__karma__.start
});

Here is the test file -- types.tests.ts

import Types = require("./../../core/types");

describe("isUndefined", () =>
{
    it("should return true when the object is undefined", () =>
    {
    });
});

and here is the thing I'm trying to test.

class Types {
    public static isNull(value: any) : boolean
    {
        return false;
    }

    public static isUndefined(value: any) : boolean
    {
        return false;
    }

    public static isString(value: any) : boolean
    {
        return false;
    }

    public static isElement(value: any) : boolean
    {
        return false;
    }

    public static isNumber(value: any) : boolean
    {
        return false;
    }
}

export = Types;

Finally, here is the error I'm getting.

INFO [IE 9.0.0 (Windows 7)]: Connected on socket H-LT4D3cwsrYq1V01VdY with id manual-4093
IE 9.0.0 (Windows 7) ERROR
  Mismatched anonymous define() module: function(require, exports) {
      describe("isUndefined", function () {
          it("should return true when the object is undefined", function () {
          });
      });
  }
  http://requirejs.org/docs/errors.html#mismatch
  at D:/Projects/Code/Development/Visual Studio/tsToolkit/node_modules/requirejs/require.js:141

NOTES:

I tried to edit the produced .js file of the test and use named modules just to make sure everything works and it does! but I guess that it doesn't make a lot of sense to go through each test and add a name to the produced .js file, isn't?

define("core/types", ["require", "exports"], function(require, exports) {
    describe("isUndefined", function () {
        it("should return true when the object is undefined", function () {
        });
    });
});
//# sourceMappingURL=types.tests.js.map

I'm sure that after so many iterations on TypeScript they haven't missed it, I hope. :p

I guess that I can write some code that automatically name these modules properly because I'm using a build file anyway but I really don't want to add extra work that can probably be saved, again, I hope.

回答1:

It tooks me few days to figure it out, the paths were incorrect all over the place both in my Karma configuration files and the requirejs 'tests.main.js' file.

I also changed the project structure so here is everything that I changed to make it work.

The solution is now available at GitHub.

The directory structure of the project.

.
|-- node_modules
|   |-- jake
|   |   |-- bin
|   |   |-- lib
|   |   |-- node_modules
|   |   |-- test
|   |   |-- Jakefile
|   |   |-- Makefile
|   |   |-- README.md
|   |   `-- package.json
|   |-- jasmine-node
|   |   |-- bin
|   |   |-- lib
|   |   |-- node_modules
|   |   |-- scripts
|   |   |-- spec
|   |   |-- src
|   |   |-- Gruntfile.coffee
|   |   |-- LICENSE
|   |   |-- README.md
|   |   |-- bower.json
|   |   |-- index.js
|   |   `-- package.json
|   |-- karma
|   |   |-- bin
|   |   |-- lib
|   |   |-- node_modules
|   |   |-- static
|   |   |-- CHANGELOG.md
|   |   |-- LICENSE
|   |   |-- README.md
|   |   |-- config.tpl.coffee
|   |   |-- config.tpl.js
|   |   |-- config.tpl.ls
|   |   |-- karma-completion.sh
|   |   |-- package.json
|   |   |-- requirejs.config.tpl.coffee
|   |   `-- requirejs.config.tpl.js
|   |-- karma-jasmine
|   |   |-- lib
|   |   |-- LICENSE
|   |   |-- README.md
|   |   `-- package.json
|   |-- karma-requirejs
|   |   |-- lib
|   |   |-- LICENSE
|   |   |-- README.md
|   |   `-- package.json
|   |-- karma-requirejs-preprocessor
|   |   `-- index.js
|   |-- requirejs
|   |   |-- bin
|   |   |-- README.md
|   |   |-- package.json
|   |   `-- require.js
|   `-- shelljs
|       |-- bin
|       |-- scripts
|       |-- src
|       |-- LICENSE
|       |-- README.md
|       |-- global.js
|       |-- make.js
|       |-- package.json
|       `-- shell.js
|-- src
|   |-- css
|   |-- framework
|   |   |-- core
|   |   `-- widgets
|   |-- libs
|   |   |-- typings
|   |   |-- jquery-2.1.0.js
|   |   `-- require.js
|   |-- tests
|   |   |-- core
|   |   `-- test.main.js
|   |-- app.main.js
|   |-- app.main.js.map
|   |-- app.main.ts
|   |-- index.html
|   |-- tsToolkit.csproj
|   |-- tsToolkit.csproj.user
|   |-- web.Debug.config
|   |-- web.Release.config
|   `-- web.config
|-- tools
|   `-- karma
|       `-- karma.conf.js
|-- WebEssentials-Settings.json
|-- jake.sh
|-- jakefile.js
|-- karma.sh
|-- scratchpad.txt
|-- tsToolkit.sln
|-- tsToolkit.sln.DotSettings.user
`-- tsToolkit.v12.suo

40 directories, 57 files

The Karma configuration file.

// Karma configuration
// Generated on Fri May 16 2014 08:27:07 GMT+0300 (Jerusalem Daylight Time)

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

        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: '../../',


        // frameworks to use
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['jasmine', 'requirejs'],


        // list of files / patterns to load in the browser
        files: [
            {pattern: 'src/libs/*.js', included: false},
            {pattern: 'src/framework/**/*.js', included: false},
            {pattern: 'src/tests/**/*.tests.js', included: false},
            'src/tests/test.main.js'
        ],


        // list of files to exclude
        exclude: [
            'src/app.main.js'
        ],


        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {

        },


        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress'],


        // web server port
        port: 8380,


        // enable / disable colors in the output (reporters and logs)
        colors: true,


        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,


        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: true,


        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: [],


        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: false
    });
};

Here is the requirejs file -- types.tests.js

var tests = [];
for (var file in window.__karma__.files) {
    if (/\.tests\.js$/.test(file)) {
        tests.push(file);
    }
}

requirejs.config({
    baseUrl: '/base/src',

    deps: tests,

    callback: window.__karma__.start
});

An example of a class that I wanted to test which is written in TypeScript -- types.ts

class Types {
    public static isNull(value: any) : boolean
    {
        return false;
    }

    public static isUndefined(value: any) : boolean
    {
        return false;
    }

    public static isString(value: any) : boolean
    {
        return false;
    }

    public static isElement(value: any) : boolean
    {
        return false;
    }

    public static isNumber(value: any) : boolean
    {
        return false;
    }
}

export = Types;

and finally, a test that I wrote for the function 'isUndefined' -- types.tests.ts

import Types = require("framework/core/types");

describe("isUndefined", () => {

    it("should return true when the object is undefined", () => {
        // Arrange
        var obj;

        // Act
        var value = Types.isUndefined(obj);

        // Assert
        expect(value).toBe(true);
    });

});

I hope that it's clear enough and that it will help others that are struggling with the same problem.

P.S. even though I wrote a requirejs-preprocessor for Karma to name my modules, after these changes i didn't need it and it just worked.



回答2:

Would changing types.tests.ts to be wrapped in a module help? Also, I'm assuming that you're using the -m AMD switch when compiling (or have AMD selected in VS)

import Types = require("./../../core/types");

module CoreTypes {
    describe("isUndefined", () => {
        it("should return true when the object is undefined", () => {
        });
    });
}

export = CoreTypes;

That doesn't name the external module (which as far as I know there is not a way to do in TypeScript 1.0), but it does at least properly wrap it as an external module.

For example, take a look at this open issue: https://typescript.codeplex.com/workitem/2394