جافاسكريبت - مشكلة في جعل TypeScript و Karma و RequireJS و Chai تعمل معًا


أنا أحاول إعادة كتابة أحد مشاريعي باستخدام TypeScript وبما أنني جديد نوعاً ما في TypeScript و RequireJS، لست متأكدًا مما أفتقده.

لقد اتبعت هذا الدليل Karma - RequireJS وتحققت من كل شيء مرتين، ومع ذلك لم أتمكن من جعله يعمل، على الأقل لم يعمل RequireJS.

ملاحظة: الخطأ الذي أحصل عليه يكون في نهاية المنشور.

هيكل الدليل الذي أستخدمه لهذا المشروع هو كما يلي:

.
|-- 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

إليك ملف التكوين الذي أستخدمه لـ 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
  });
};

إليك التكوين الذي لدي لـ 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
});

إليك ملف الاختبار -- types.tests.ts

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

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

وهنا الشيء الذي أحاول اختباره.

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;

أخيرًا، هذا هو الخطأ الذي أحصل عليه.

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

ملاحظات:

حاولت تعديل ملف .js الناتج من الاختبار واستخدام الوحدات المسماة فقط للتأكد من أن كل شيء يعمل وهذا ما حدث! لكن أعتقد أنه لا معنى كبير في المرور على كل اختبار وإضافة اسم لملف .js الناتج، أليس كذلك؟

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

أنا متأكد أنه بعد كل هذه التكرارات على TypeScript لم يفوتوها، آمل ذلك. :p

أعتقد أنني أستطيع كتابة بعض الكود الذي يسمي هذه الوحدات بشكل صحيح تلقائيًا لأنني أستخدم ملف بناء على أي حال، لكنني لا أريد حقًا إضافة عمل إضافي يمكن على الأرجح توفيره، مرة أخرى، آمل ذلك.

الإجابة رقم 1

استغرق الأمر مني عدة أيام لأفهم الأمر، كانت المسارات غير صحيحة في كل مكان سواء في ملفات تكوين Karma الخاصة بي أو في ملف requirejs 'tests.main.js'.

لقد قمت أيضًا بتغيير هيكل المشروع، فإليك كل شيء قمت بتغييره لجعله يعمل.

الحل متاح الآن على GitHub.

هيكلية مجلدات المشروع.

.
|-- 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

ملف إعدادات Karma.

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

إليك ملف requirejs -- 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
});

مثال على فئة أردت اختبارها مكتوبة بلغة 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;

وأخيرًا، اختبار كتبته للدالة '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);
    });

});

آمل أن يكون ذلك واضحًا بما فيه الكفاية وأن يساعد الآخرين الذين يعانون من نفس المشكلة.

ملاحظة: بالرغم من أنني كتبت مهيئ مسبق لـ RequireJS لـ Karma لتسمية وحداتي، بعد هذه التغييرات لم أعد بحاجة إليه وفقط عمل كل شيء.

الإجابة رقم 2

هل قد يساعد تغيير types.tests.ts ليكون ملفًا محاطًا بوحدة؟ أيضًا، أفترض أنك تستخدم الخيار -m AMD عند التجميع (أو لديك AMD محدد في VS)

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

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

export = CoreTypes;

ذلك لا يسمي الوحدة الخارجية (والتي على حد علمي لا توجد طريقة للقيام بذلك في TypeScript 1.0)، لكنه على الأقل يغلفها بشكل صحيح كوحدة خارجية.

على سبيل المثال، ألقِ نظرة على هذه المشكلة المفتوحة: https://typescript.codeplex.com/workitem/2394