スタンドアロンのJavascriptコードを開発する方法を理解しようとしています。コマンドラインから実行するテストとモジュールを含むJavscriptコードを記述したいと思います。そこで、node.js
およびnpm
をライブラリrequirejs
、underscore
、および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);
})
})
});
次に、トップレベルのディレクトリから実行しようとします(したがって、mocha
はtest
ディレクトリを参照します)。
> 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)
...
だから私の質問は:
ありがとう...
[申し訳ありません-間違ったコードから結果を一時的に投稿しました。今すぐ修正]
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)
テストが実行されない理由は、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を好んでいます。
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
ブラウザ(AMD)用に設計されたJSモジュールを実行しようとしていますが、バックエンドでは動作しない可能性があります(モジュールはcommonjsの方法でロードされるため)。このため、次の2つの問題に直面します。
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();
})
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
モジュールが含まれています。