it-swarm.com.de

Die Voraussetzungen schaffen, um mit Jasmine zu arbeiten

Ich möchte zuerst sagen, dass ich neu bei RequireJS und noch neuer bei Jasmine bin.

Ich habe einige Probleme mit dem SpecRunner und benötige JS. Ich habe die Tutorials von Uzi Kilon und Ben Nadel (zusammen mit einigen anderen) verfolgt und sie haben einigen geholfen, aber ich habe immer noch einige Probleme.

Es scheint, dass, wenn es einen Fehler gibt, der im Test ausgelöst wird (ich kann mir einen bestimmten vorstellen, einen Typfehler), der Spezifikationsläufer-HTML angezeigt wird. Dies sagt mir, dass ich einige Probleme im Javascript habe. Nachdem ich diesen Fehler behoben habe, wird kein HTML mehr angezeigt. Ich kann den Testrunner überhaupt nicht anzeigen lassen. Kann jemand einen Fehler mit meinem Code finden, der dieses Problem verursachen würde?

Hier ist mein Verzeichnisstruktur:

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

Hier ist der SpecRunner (index) 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>

Hier ist die specRunner.js (config)

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

Hier ist eine Spezifikation:

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


    });
});

Die Notizblockquelle:

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

Und die Notenquelle (JIC):

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

    return note;
});

Ich habe dafür gesorgt, dass die Pfade für die App korrekt sind. Sobald ich das zum Laufen gebracht habe, kann ich damit spielen, diese Pfade so zu konfigurieren, dass es nicht so schlimm ist.

66
The Sheek Geek

Ich habe es geschafft, dies mit ein wenig Versuch und Irrtum zum Laufen zu bringen. Das Hauptproblem bestand darin, dass Sie beim Schreiben von Spezifikationen nicht die folgenden Anforderungen erstellen, sondern define verwenden möchten:

Original:

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


    });
});

Working:

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

        it("something", function() {

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

    });
});

Nach einigen Recherchen wurde klar, dass bei der Verwendung von RequireJS alles, was mit require () verwendet werden soll, in ein Define eingeschlossen werden muss (was jetzt offensichtlich erscheint, denke ich). Sie können sehen, dass in der Datei specRunner.js eine Anforderung verwendet wird, wenn die Tests ausgeführt werden (daher müssen die Spezifikationen "definiert" werden.

Das andere Problem ist, dass beim Erstellen von Spezifikationen die Anweisung describe () UND die Anweisung it () erforderlich sind (nicht nur die Anweisung describe, wie ich sie im angegebenen Beispiel angegeben habe).

Original:

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


    });

Working:

describe("returns titles", function () {

        it("something", function() {

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

    });

Ich habe auch geändert, wo der Testläufer vorhanden ist, aber dies war ein Refaktor und hat das Ergebnis der Tests nicht geändert.

Auch hier sind die Dateien und die geänderten:

note.js: ist gleich geblieben

notepad.js: ist gleich geblieben

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

    });
});
57
The Sheek Geek

Fügen Sie dies einfach als alternative Antwort für Personen hinzu, die Jasmine 2.0 als eigenständige Version verwenden. Ich glaube, dass dies auch für Jasmine 1.3 funktionieren kann, aber die asynchrone Syntax ist anders und irgendwie hässlich.

Hier ist meine modifizierte SpecRunner.html-Datei:

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

Hier ist eine Beispielspezifikationsdatei:

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

Hier ist ein Link zum Abschnitt Async-Support aus den Jasmine 2.0-Dokumenten: http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support

12
Gohn67

Eine weitere Option für Jasmine 2.0 ist das Erstellen einer boot.js-Datei und deren Einrichtung, um Ihre Tests auszuführen, nachdem alle AMD-Module geladen wurden.

In unserem Fall bestand der ideale Endbenutzerfall für das Schreiben von Tests darin, nicht alle unsere Spezifikationsdateien oder Abhängigkeiten in einer einmaligen expliziten Liste auflisten zu müssen und nur Ihre * Spezifikationsdateien als AMD-Module mit Abhängigkeiten zu deklarieren.

Beispiel ideale Spezifikation: 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();
      });
  });
});

Im Idealfall ist das Hintergrundverhalten beim Laden der Abhängigkeit in die Spezifikation und beim Ausführen der Spezifikation für alle Benutzer, die Tests schreiben möchten, völlig undurchsichtig, und sie müssen lediglich eine * spec.js-Datei mit AMD-Abhängigkeiten erstellen .

Um dies alles zum Laufen zu bringen, haben wir eine Boot-Datei erstellt und Jasmine für die Verwendung konfiguriert ( http://jasmine.github.io/2.0/boot.html ) Um laufende Tests vorübergehend zu verzögern, bis wir unsere Deps geladen haben:

Unsere boot.js '"Execution" Sektion:

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

};

Grundsätzlich halten wir unsere AMD-Syntaxspezifikationen in einem Stapel, entfernen sie, fordern die Module an, führen den Rückruf mit unseren Behauptungen aus und führen dann Jasmine aus, sobald alles geladen ist.

Mit dieser Einstellung können wir warten, bis alle für unsere einzelnen Tests erforderlichen AMD-Module geladen sind, und AMD-Muster nicht durch Erstellen von Globals auflösen. Die Tatsache, dass wir require vorübergehend überschreiben und unseren App-Code nur mit require (our `src_dir: in jasmine.yml ist leer, aber das übergeordnete Ziel ist hier, den Aufwand für das Schreiben einer Spezifikation zu reduzieren.

3
TopherBullock

sie können done in Kombination mit Vor-Filtern verwenden, um asynchrone Rückrufe zu testen:

  beforeEach(function(done) {
    return require(['dist/sem-campaign'], function(campaign) {
      module = campaign;
      return done();
    });
  });
3
lfender6445

So führe ich eine Jasminspezifikation in einem HTML-Code mit AMD/requirejs für alle meine Quellen und Spezifikationen aus.

Dies ist meine index.html-Datei, die Jasmin und dann meinen 'Unit-Test-Starter' lädt:

<html><head><title>unit test</title><head>
<link rel="shortcut icon" type="image/png" href="/jasmine/lib/jasmine-2.1.3/jasmine_favicon.png">
<link rel="stylesheet" href="/jasmine/lib/jasmine-2.1.3/jasmine.css">
<script src="/jasmine/lib/jasmine-2.1.3/jasmine.js"></script>
<script src="/jasmine/lib/jasmine-2.1.3/jasmine-html.js"></script>
<script src="/jasmine/lib/jasmine-2.1.3/boot.js"></script>
</head><body>
<script data-main="javascript/UnitTestStarter.js" src="javascript/require.js"></script>
</body></html>

und dann ist mein UnitTestStarter.js ungefähr so:

require.config({
    "paths": {
        ....
});
require(['MySpec.js'], function()
{
    jasmine.getEnv().execute();
})
1
cancerbero