web-dev-qa-db-fra.com

Pourquoi est-ce que je vois "définir non défini" lors de l'exécution d'un test Mocha avec RequireJS?

J'essaie de comprendre comment développer du code Javascript autonome. Je veux écrire du code Javscript avec des tests et des modules, à partir de la ligne de commande. J'ai donc installé node.js et npm ainsi que les bibliothèques requirejs, underscore et mocha.

Ma structure de répertoire ressemble à ceci:

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

src/utils.js est un petit module que j'écris, avec le code suivant:

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

});

et test/utils.js est le test:

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

});

que j'essaie ensuite d'exécuter à partir du répertoire de niveau supérieur (donc mocha voit le répertoire 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)
    ...

Mes questions sont donc:

  • Est-ce la bonne façon de structurer le code?
  • Pourquoi mon test ne fonctionne-t-il pas?
  • Quelle est la meilleure façon d'apprendre ce genre de chose? J'ai du mal à trouver de bons exemples avec Google.

Merci...

[désolé - résultats momentanément affichés à partir d'un mauvais code; réparé maintenant]

PS J'utilise requirejs parce que je veux aussi exécuter ce code (ou une partie) à partir d'un navigateur, plus tard.

Mise à jour/Solution

Quelque chose qui ne figure pas dans les réponses ci-dessous est que je devais utiliser mocha -u tdd pour le style de test ci-dessus. Voici le test final (qui nécessite également assert) et son utilisation:

> 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

La raison pour laquelle votre test ne s'exécute pas est parce que src/utils.js n'est pas une bibliothèque Node.js valide.

Selon la documentation RequireJS, afin de coexister avec Node.js et CommonJS nécessitent la norme, vous devez ajouter un peu de passe-partout en haut de votre src/utils.js file afin que la fonction define de RequireJS soit chargée.

Cependant, étant donné que RequireJS a été conçu pour pouvoir exiger du code source orienté navigateur Web "classique", j'ai tendance à utiliser le modèle suivant avec mes bibliothèques Node.js que je souhaite également exécuter dans le navigateur:

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

// Insert code here

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

Cela a l'avantage de ne pas nécessiter de bibliothèque supplémentaire pour les autres utilisateurs de Node.js et fonctionne généralement bien avec RequireJS sur le client.

Une fois votre code exécuté dans Node.js, vous pouvez commencer les tests. Personnellement, je préfère toujours expresso à moka, même si c'est le cadre de test successeur.

18
David Ellis

La documentation Mocha manque sur la façon de configurer ces choses, et il est perplexe de comprendre à cause de tous les tours de magie qu'il fait sous le capot.

J'ai trouvé les clés pour obtenir les fichiers du navigateur en utilisant require.js pour travailler dans Mocha sous Node: Mocha has pour que les fichiers soient ajoutés à ses suites avec addFile:

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

Et deuxièmement, utilisez beforeEach avec le rappel facultatif pour charger vos modules de manière asynchrone:

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

J'ai créé un bootstrap pour savoir comment tout cela fonctionne: https://github.com/clubajax/mocha-bootstrap

5
mwilcox

Vous essayez d'exécuter des modules JS conçus pour les navigateurs (AMD), mais dans le backend cela peut ne pas fonctionner (car les modules sont chargés de la manière commonjs). Pour cette raison, vous serez confronté à deux problèmes:

  1. définir n'est pas défini
  2. 0 test exécuté

Dans le navigateur, define sera défini. Il sera défini lorsque vous demanderez quelque chose avec requirejs. Mais nodejs charge les modules de la manière commune. define dans ce cas n'est pas défini. Mais il sera défini lorsque nous aurons besoin de requirejs!

Cela signifie que maintenant nous demandons du code de manière asynchrone, et cela pose le deuxième problème, un problème avec l'exécution asynchrone. https://github.com/mochajs/mocha/issues/362

Voici un exemple de travail complet. Regardez que j'ai dû configurer requirejs (AMD) pour charger les modules, nous n'utilisons pas require (node ​​/ commonjs) pour charger nos modules.

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

})

Et pour le module que vous souhaitez tester:

> 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

Juste au cas où réponse de David n'était pas assez clair, j'avais juste besoin d'ajouter ceci:

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

En haut du fichier js où j'utilise define, comme décrit dans les documents RequireJS ( "Création de modules de noeud avec AMD ou RequireJS" ) et dans le même dossier, ajoutez le amdefine package:

npm install amdefine

Cela crée le node_modules dossier avec le module amdefine à l'intérieur.

0
Armfoot