67

最初に言いたいのは、私は RequireJS の初心者であり、Jasmine の初心者です。

SpecRunner に問題があり、JS が必要です。私は Uzi Kilon と Ben Nadel のチュートリアルに従っています (他のいくつかのチュートリアルと一緒に)。

テストでエラーがスローされた場合 (特に型エラーが考えられます)、spec runner html が表示されるようです。これは、javascript に問題があることを示しています。ただし、これらのエラーを修正すると、HTML が表示されなくなります。 テストランナーをまったく表示できません。この問題の原因となる私のコードの問題を誰かが見つけることができますか?

ここに私のディレクトリ構造があります:

Root 
|-> lib
    |-> jasmine
        |-> lib (contains all of the jasmine lib)
        |-> spec
        |-> src
    |-> jquery (jquery js file)
    |-> require (require js file) 
index.html (spec runner) specRunner.js

SpecRunner (インデックス) HTMLは次のとおりです。

<!doctype html>
<html lang="en">
    <head>
        <title>Javascript Tests</title>

        <link rel="stylesheet" href="lib/jasmine/lib/jasmine.css">

        <script src="lib/jasmine/lib/jasmine.js"></script>
        <script src="lib/jasmine/lib/jasmine-html.js"></script>
        <script src="lib/jquery/jquery.js"></script>
        <script data-main="specRunner" src="lib/require/require.js"></script>

        <script>
            require({ paths: { spec: "lib/jasmine/spec" } }, [
                    // Pull in all your modules containing unit tests here.
                    "spec/notepadSpec"
                ], function () {
                    jasmine.getEnv().addReporter(new jasmine.HtmlReporter());
                    jasmine.getEnv().execute();
                });
        </script>

    </head>

<body>
</body>
</html>

これがspecRunner.js(構成)です

require.config({
    urlArgs: 'cb=' + Math.random(),
    paths: {
        jquery: 'lib/jquery',
        jasmine: 'lib/jasmine/lib/jasmine',
        'jasmine-html': 'lib/jasmine/lib/jasmine-html',
        spec: 'lib/jasmine/spec/'
    },
    shim: {
        jasmine: {
            exports: 'jasmine'
        },
        'jasmine-html': {
            deps: ['jasmine'],
            exports: 'jasmine'
        }
    }
});

ここに仕様があります:

require(["../lib/jasmine/src/notepad"], function (notepad) {
    describe("returns titles", function() {
        expect(notepad.noteTitles()).toEqual("");


    });
});

メモ帳のソース:

define(['lib/jasmine/src/note'], function (note) {

    var notes = [
        new note('pick up the kids', 'dont forget to pick  up the kids'),
        new note('get milk', 'we need two gallons of milk')
    ];


    return {
        noteTitles: function () {
            var val;

            for (var i = 0, ii = notes.length; i < ii; i++) {
                //alert(notes[i].title);
                val += notes[i].title + ' ';
            }

            return val;
        }
    };
});

そしてメモのソース (JIC):

define(function (){
    var note = function(title, content) {
        this.title = title;
        this.content = content;
    };

    return note;
});

アプリに関する限り、パスが正しいことを確認しました。これが機能するようになったら、そのパスを構成して遊ぶことができるので、それほど厄介ではありません。

4

5 に答える 5

58

私は試行錯誤を重ねてこれを機能させることができました。主な問題は、spec を作成するときに、作成する必要があるのではなく、define を使用する必要があるということでした。

オリジナル:

require(["/lib/jasmine/src/notepad"], function (notepad) {
    describe("returns titles", function() {
        expect(notepad.noteTitles()).toEqual("pick up the kids get milk");


    });
});

働く:

define(["lib/jasmine/src/notepad"], function (notepad) {
    describe("returns titles", function () {

        it("something", function() {

            expect(notepad.noteTitles()).toEqual("pick up the kids get milk ");
        });

    });
});

いくつかの調査を行った後、RequireJS を使用する場合、require() で使用するものはすべて定義でラップする必要があることが明らかになりました (今では明らかだと思います)。specRunner.js ファイルでは、テストの実行時に require が使用されていることがわかります (したがって、spec.js を「定義」する必要があります)。

もう 1 つの問題は、仕様を作成するときに、describe() と it() が必要であることです (投稿された例のような記述だけではありません)。

オリジナル:

describe("returns titles", function() {
        expect(notepad.noteTitles()).toEqual("pick up the kids get milk");


    });

働く:

describe("returns titles", function () {

        it("something", function() {

            expect(notepad.noteTitles()).toEqual("pick up the kids get milk ");
        });

    });

テストランナーが存在する場所も変更しましたが、これはリファクタリングであり、テストの結果は変わりませんでした。

繰り返しますが、ファイルと変更されたものは次のとおりです。

note.js:そのまま

notepad.js:そのまま

index.html:

<!doctype html>
<html lang="en">
    <head>
        <title>Javascript Tests</title>
        <link rel="stylesheet" href="lib/jasmine/lib/jasmine.css">
        <script data-main="specRunner" src="lib/require/require.js"></script>
    </head>

    <body>
    </body>
</html>

specRunner.js:

require.config({
    urlArgs: 'cb=' + Math.random(),
    paths: {
        jquery: 'lib/jquery',
        'jasmine': 'lib/jasmine/lib/jasmine',
        'jasmine-html': 'lib/jasmine/lib/jasmine-html',
        spec: 'lib/jasmine/spec/'
    },
    shim: {
        jasmine: {
            exports: 'jasmine'
        },
        'jasmine-html': {
            deps: ['jasmine'],
            exports: 'jasmine'
        }
    }
});


require(['jquery', 'jasmine-html'], function ($, jasmine) {

    var jasmineEnv = jasmine.getEnv();
    jasmineEnv.updateInterval = 1000;

    var htmlReporter = new jasmine.HtmlReporter();

    jasmineEnv.addReporter(htmlReporter);

    jasmineEnv.specFilter = function (spec) {
        return htmlReporter.specFilter(spec);
    };

    var specs = [];

    specs.push('lib/jasmine/spec/notepadSpec');



    $(function () {
        require(specs, function (spec) {
            jasmineEnv.execute();
        });
    });

});

notepadSpec.js:

define(["lib/jasmine/src/notepad"], function (notepad) {
    describe("returns titles", function () {

        it("something", function() {

            expect(notepad.noteTitles()).toEqual("pick up the kids get milk");
        });

    });
});
于 2013-05-13T16:49:37.433 に答える
12

Jasmine 2.0 スタンドアロンを使用している人々のための代替回答としてこれを追加するだけです。これはJasmine 1.3でも機能すると思いますが、非同期構文は異なり、醜いものです。

変更した SpecRunner.html ファイルは次のとおりです。

<!DOCTYPE HTML>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Jasmine Spec Runner v2.0.0</title>

  <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.0.0/jasmine_favicon.png">
  <link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.0/jasmine.css">

  <!-- 
  Notice that I just load Jasmine normally
  -->    
  <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine.js"></script>
  <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine-html.js"></script>
  <script type="text/javascript" src="lib/jasmine-2.0.0/boot.js"></script>

  <!-- 
  Here we load require.js but we do not use data-main. Instead we will load the
  the specs separately. In short we need to load the spec files synchronously for this
  to work.
  -->
  <script type="text/javascript" src="js/vendor/require.min.js"></script>

  <!-- 
  I put my require js config inline for simplicity
  -->
  <script type="text/javascript">
    require.config({
      baseUrl: 'js',
      shim: {
          'underscore': {
              exports: '_'
          },
          'react': {
              exports: 'React'
          }
      },
      paths: {
          jquery: 'vendor/jquery.min',
          underscore: 'vendor/underscore.min',
          react: 'vendor/react.min'
      }
    });
  </script>

  <!-- 
  I put my spec files here
  -->
  <script type="text/javascript" src="spec/a-spec.js"></script>
  <script type="text/javascript" src="spec/some-other-spec.js"></script>
</head>

<body>
</body>
</html>

次に、spec ファイルの例を示します。

describe("Circular List Operation", function() {

    // The CircularList object needs to be loaded by RequireJs
    // before we can use it.
    var CircularList;

    // require.js loads scripts asynchronously, so we can use
    // Jasmine 2.0's async support. Basically it entails calling
    // the done function once require js finishes loading our asset.
    //
    // Here I put the require in the beforeEach function to make sure the
    // Circular list object is loaded each time.
    beforeEach(function(done) {
        require(['lib/util'], function(util) {
            CircularList = util.CircularList;
            done();
        });
    });

    it("should know if list is empty", function() {
        var list = new CircularList();
        expect(list.isEmpty()).toBe(true);
    });

    // We can also use the async feature on the it function
    // to require assets for a specific test.
    it("should know if list is not empty", function(done) {
        require(['lib/entity'], function(entity) {
            var list = new CircularList([new entity.Cat()]);
            expect(list.isEmpty()).toBe(false);
            done();
        });
    });
});

Jasmine 2.0 ドキュメントの非同期サポート セクションへのリンクは次のとおりです: http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support

于 2014-01-24T23:30:40.700 に答える
3

Jasmine 2.0 スタンドアロンのもう 1 つのオプションは、boot.js ファイルを作成し、すべての AMD モジュールがロードされた後にテストを実行するように設定することです。

私たちのケースでテストを作成するための理想的なエンド ユーザー ケースは、spec ファイルまたは依存関係のすべてを 1 回の明示的なリストにリストする必要はなく、依存関係を持つ AMD モジュールとして *spec ファイルを宣言する必要があるだけでした。

理想的な仕様の例: spec/javascript/sampleController_spec.js

require(['app/controllers/SampleController'], function(SampleController) {
  describe('SampleController', function() {
      it('should construct an instance of a SampleController', function() {
        expect(new SampleController() instanceof SampleController).toBeTruthy();
      });
  });
});

依存関係を読み込んで仕様を実行するバックグラウンド動作が、テストを書きたいプロジェクトに参加する人にとって完全に不透明であり、AMD の依存関係を含む *spec.js ファイルを作成する以外に何もする必要がないことが理想的です。 .

これをすべて機能させるために、ブート ファイルを作成し、それを使用するように Jasmine を構成しました ( http://jasmine.github.io/2.0/boot.html )。私たちはdepをロードしました:

boot.js「実行」セクション:

/**
 * ## Execution
 *
 * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
 */

var currentWindowOnload = window.onload;

// Stack of AMD spec definitions
var specDefinitions = [];

// Store a ref to the current require function
window.oldRequire = require;

// Shim in our Jasmine spec require helper, which will queue up all of the definitions to be loaded in later.
require = function(deps, specCallback){
  //push any module defined using require([deps], callback) onto the specDefinitions stack.
  specDefinitions.push({ 'deps' : deps, 'specCallback' : specCallback });
};

//
window.onload = function() {

  // Restore original require functionality
  window.require = oldRequire;
  // Keep a ref to Jasmine context for when we execute later
  var context = this,
      requireCalls = 0, // counter of (successful) require callbacks
      specCount = specDefinitions.length; // # of AMD specs we're expecting to load

  // func to execute the AMD callbacks for our test specs once requireJS has finished loading our deps
  function execSpecDefinitions() {
    //exec the callback of our AMD defined test spec, passing in the returned modules.
    this.specCallback.apply(context, arguments);        
    requireCalls++; // inc our counter for successful AMD callbacks.
    if(requireCalls === specCount){
      //do the normal Jamsine HTML reporter initialization
      htmlReporter.initialize.call(context);
      //execute our Jasmine Env, now that all of our dependencies are loaded and our specs are defined.
      env.execute.call(context);
    }
  }

  var specDefinition;
  // iterate through all of our AMD specs and call require with our spec execution callback
  for (var i = specDefinitions.length - 1; i >= 0; i--) {
    require(specDefinitions[i].deps, execSpecDefinitions.bind(specDefinitions[i]));
  }

  //keep original onload in case we set one in the HTML
  if (currentWindowOnload) {
    currentWindowOnload();
  }

};

基本的に、AMD 構文仕様をスタックに保持し、ポップオフし、モジュールを要求し、アサーションを含むコールバックを実行し、すべての読み込みが完了したら Jasmine を実行します。

このセットアップにより、個々のテストに必要なすべての AMD モジュールがロードされるまで待つことができ、グローバルを作成することによって AMD パターンが壊れることはありません。一時的に require をオーバーライドし、require を使用してアプリ コードのみをロードする ( jasmine.yml 内`src_dir:は空です) という事実には少しハッカーがいますが、ここでの全体的な目標は、仕様を記述するオーバーヘッドを削減することです。

于 2014-02-07T19:14:54.563 に答える
3

donebefore フィルターと組み合わせて使用​​して、非同期コールバックをテストできます。

  beforeEach(function(done) {
    return require(['dist/sem-campaign'], function(campaign) {
      module = campaign;
      return done();
    });
  });
于 2014-08-28T20:09:17.867 に答える