web-dev-qa-db-ja.com

RequireJSでMochaテストを実行しているときに「define not defined」と表示されるのはなぜですか?

スタンドアロンのJavascriptコードを開発する方法を理解しようとしています。コマンドラインから実行するテストとモジュールを含むJavscriptコードを記述したいと思います。そこで、node.jsおよびnpmをライブラリrequirejsunderscore、およびmochaとともにインストールしました。

私のディレクトリ構造は次のようになります。

> tree .
.
├── node_modules
├── src
│   └── utils.js
└── test
    └── utils.js

src/utils.jsは、私が書いている小さなモジュールで、次のコードがあります:

> cat src/utils.js 
define(['underscore'], function () {

    "use strict";

    if ('function' !== typeof Object.beget) {
        Object.beget = function (o) {
            var f = function () {
            };
            f.prototype = o;
            return new f();
        };
    }

});

test/utils.jsはテストです。

> cat test/utils.js 
var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});

requirejs(['../src/utils'], function(utils) {

    suite('utils', function() {
        test('should always work', function() {
            assert.equal(1, 1);
        })
    })

});

次に、トップレベルのディレクトリから実行しようとします(したがって、mochatestディレクトリを参照します)。

> mocha

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: Calling node's require("../src/utils") failed with error: ReferenceError: define is not defined
    at /.../node_modules/requirejs/bin/r.js:2276:27
    at Function.execCb (/.../node_modules/requirejs/bin/r.js:1872:25)
    at execManager (/.../node_modules/requirejs/bin/r.js:541:31)
    ...

だから私の質問は:

  • これはコードを構造化する正しい方法ですか?
  • テストが実行されないのはなぜですか?
  • この種のことを学ぶ最良の方法は何ですか? Googleで良い例を見つけるのに苦労しています。

ありがとう...

[申し訳ありません-間違ったコードから結果を一時的に投稿しました。今すぐ修正]

PS requirejsを使用しているのは、後でこのコード(またはその一部)をブラウザーから実行するためです。

更新/ソリューション

以下の回答にないのは、上記のテストスタイルにmocha -u tddを使用する必要があるということです。最後のテスト(アサートも必要)とその使用法を次に示します。

> cat test/utils.js 

var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});

requirejs(['../src/utils', 'assert'], function(utils, assert) {

    suite('utils', function() {
        test('should always work', function() {
            assert.equal(1, 1);
        })
    })

});
> mocha -u tdd

  .

  ✔ 1 tests complete (1ms)
38
andrew cooke

テストが実行されない理由は、src/utils.jsが有効なNode.jsライブラリではないためです。

RequireJSのドキュメントによると、Node.jsおよびCommonJSが標準を必要とするためには、 ボイラープレートを少し追加src/utils.jsファイルの先頭に追加する必要があるため、RequireJSのdefine関数がロードされます。

ただし、RequireJSは「古典的な」Webブラウザ指向のソースコードを要求できるように設計されているため、Node.jsライブラリで次のパターンを使用して、ブラウザでも実行する傾向があります。

if(typeof require != 'undefined') {
    // Require server-side-specific modules
}

// Insert code here

if(typeof module != 'undefined') {
    module.exports = whateverImExporting;
}

これには、他のNode.jsユーザーのために追加のライブラリを必要としないという利点があり、通常はクライアント上のRequireJSでうまく機能します。

Node.jsでコードを実行したら、テストを開始できます。個人的には、後継テストフレームワークであるにもかかわらず、mochaよりもexpressoを好んでいます。

18
David Ellis

Mochaのドキュメントには、このようなものを設定する方法が欠けており、内部で行うすべての魔法のトリックのために、理解するのは困惑しています。

require.jsを使用してブラウザーファイルを取得するためのキーが見つかりました。これはNode:MochahasaddFileでスイートにファイルを追加するには:

mocha.addFile('lib/tests/Main_spec_node');

次に、オプションのコールバックでbeforeEachを使用して、モジュールを非同期にロードします。

describe('Testing "Other"', function(done){
    var Other;
    beforeEach(function(done){
        requirejs(['lib/Other'], function(_File){
            Other = _File;
            done(); // #1 Other Suite will run after this is called
        });
    });

    describe('#1 Other Suite:', function(){
        it('Other.test', function(){
            chai.expect(Other.test).to.equal(true);
        });
    });
});

私はbootstrapを作成し、これをすべて機能させる方法について: https://github.com/clubajax/mocha-bootstrap

5
mwilcox

ブラウザ(AMD)用に設計されたJSモジュールを実行しようとしていますが、バックエンドでは動作しない可能性があります(モジュールはcommonjsの方法でロードされるため)。このため、次の2つの問題に直面します。

  1. 定義は定義されていません
  2. 0テスト実行

Browser defineで定義されます。 requirejsで何かを必要とするときに設定されます。ただし、nodejsはモジュールをcommonjsの方法でロードします。この場合のdefineは定義されていません。ただし、requirejsで必要な場合に定義されます!

これは、現在コードを非同期的に要求していることを意味し、2番目の問題、非同期実行の問題をもたらします。 https://github.com/mochajs/mocha/issues/362

完全な動作例を次に示します。モジュールをロードするためにrequirejs(AMD)を構成する必要がありましたが、モジュールをロードするためにrequire(node/commonjs)を使用していません。

> cat $PROJECT_HOME/test/test.js

var requirejs = require('requirejs');
var path = require('path')
var project_directory = path.resolve(__dirname, '..')

requirejs.config({
  nodeRequire: require, 
  paths: {
    'widget': project_directory + '/src/js/some/widget'
  }
});

describe("Mocha needs one test in order to wait on requirejs tests", function() {
  it('should wait for other tests', function(){
    require('assert').ok(true);
  });
});


requirejs(['widget/viewModel', 'assert'], function(model, assert){

  describe('MyViewModel', function() {
    it("should be 4 when 2", function () {
        assert.equal(model.square(2),4)
    })
  });

})

そして、テストしたいモジュールに対して:

> cat $PROJECT_HOME/src/js/some/widget/viewModel.js

define(["knockout"], function (ko) {

    function VideModel() {
        var self = this;

        self.square = function(n){
            return n*n;
        }

    }

    return new VideModel();
})
1
David Rz Ayala

David's answer が十分に明確でない場合に備えて、これを追加する必要がありました。

if (typeof define !== 'function') {
    var define = require('amdefine')(module);
}

RequireJS docs( 「AMDまたはRequireJSを使用したノードモジュールの構築」 )で説明されているように、defineを使用するjsファイルの先頭に、同じフォルダーにamdefineパッケージ:

npm install amdefine

これにより、node_modulesフォルダーにamdefineモジュールが含まれています。

0
Armfoot