2012-02-16 9 views
35

Sto cercando di capire come sviluppare codice JavaScript stand-alone. Voglio scrivere codice Javscript con test e moduli, in esecuzione dalla riga di comando. Quindi ho installato node.js e npm insieme alle librerie requirejs, underscore e mocha.Perché vedo "definire non definito" quando si esegue un test Mocha con RequireJS?

mia struttura di directory simile a questo:

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

dove src/utils.js è un piccolo modulo che sto scrivendo, con il seguente codice:

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

}); 

e test/utils.js è il 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); 
     }) 
    }) 

}); 

che poi provo a eseguire dalla directory di livello superiore (così mocha vede la directory 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) 
    ... 

Quindi le mie domande sono:

  • E 'questo il modo corretto di strutturare il codice?
  • Perché il test non è in esecuzione?
  • Qual è il modo migliore per imparare questo genere di cose? Ho difficoltà a trovare buoni esempi con Google.

Grazie ...

[dispiace - momentaneamente pubblicato i risultati di codice errato; risolto ora]

PS Sto usando requirejs perché voglio anche eseguire questo codice (o parte di esso) da un browser, in seguito.

Aggiornamento/Soluzione

Qualcosa che non è nelle risposte qui sotto è che avevo bisogno di usare mocha -u tdd per lo stile di prova di cui sopra. Ecco la prova finale (che richiede anche assert) e il suo uso:

> 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) 
+0

Per far sì che funzioni, devo installare il modulo amdefine e aggiungere questi coffeescript di riga = >> define = require ('amdefine') (module) if (typeof define! = 'Function') << = in il mio file 'classe' per farlo funzionare (non il file di test). Questo è un po 'fastidioso dal momento che è necessario avere un compito per rimuovere questo dopo aver testato – devric

risposta

15

Il motivo per cui il test non è in esecuzione è perché src/utils.js non è una libreria Node.js valida.

Secondo la documentazione RequireJS, al fine di coesistere con Node.js ei CommonJS richiedono standard, è necessario add a bit of boilerplate alla parte superiore del file src/utils.js così la funzione di RequireJS define viene caricato.

Tuttavia, poiché RequireJS è stato progettato per essere in grado di richiedere il codice sorgente del browser web-oriented "classico", tendo a usare lo schema seguente con le mie librerie Node.JS che voglio anche in esecuzione nel browser:

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

// Insert code here 

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

Questo ha il vantaggio di non richiedere una libreria aggiuntiva per altri utenti Node.js e generalmente funziona bene con RequireJS sul client.

Una volta eseguito il codice in Node.js, è possibile iniziare il test. Personalmente preferisco ancora l'espresso con la moka, anche se è il framework dei test successivi.

+1

grazie! Suppongo che tu non sappia anche cosa devo fare per ottenere la "suite" (da moka) da definire, dato che con il boilerplate il mio test ora fallisce su questo? inoltre, stai dicendo che "define" non funzionerà per il codice del browser? Non capisco la tua motivazione per l'approccio alternativo di cui sopra - è "solo" una questione di stile? –

+0

ah, capisco il tuo punto: non vuoi definire i nodi per i browser web. –

+0

Non è troppo difficile, ti manca il '' require ('mocha') '' boilerplate. [Presa direttamente dalla bocca del cavallo] (https://github.com/visionmedia/mocha/blob/master/test/suite.js) è la risposta. (Sono nuovo di StackOverflow, non sapevo che non si potesse avere codice sorgente multilinea nei commenti.) –

-1

Non faccio uso di requirejs quindi non sono sicuro di quello che la sintassi assomiglia, ma questo è quello che faccio per eseguire codice sia all'interno node e la browser:

Per le importazioni, determinare se ci sono in esecuzione nel nodo o il browser:

var root = typeof exports !== "undefined" && exports !== null ? exports : window; 

Poi ci può afferrare le dipendenze correttamente (saranno entrambi disponibili già se nel browser o usiamo require):

var foo = root.foo; 
if (!foo && (typeof require !== 'undefined')) { 
    foo = require('./foo'); 
} 

var Bar = function() { 
    // do something with foo 
} 

E poi qualsiasi funzionalità che deve essere utilizzato da altri file, esportiamo a radice:

root.bar = Bar; 

Come per gli esempi, GitHub è una grande fonte.Basta andare e controllare il codice della libreria preferita per vedere come l'hanno fatto :) Ho usato mocha per testare una libreria javascript che può essere utilizzata sia nel browser che nel nodo. Il codice è disponibile allo https://github.com/bunkat/later.

4

La documentazione di Mocha è carente su come impostare questa roba, ed è perplesso capire a causa di tutti i trucchi magici che fa sotto il cofano.

ho trovato le chiavi per ottenere i file del browser mediante require.js a lavorare in Mocha sotto Node: Mocha ha avere i file aggiunti alle sue suite con addFile:

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

E in secondo luogo, utilizzare beforeEach con la richiamata opzionale per caricare i moduli in modo asincrono:

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

ho creato un bootstrap per come ottenere questo tutto funzionante: https://github.com/clubajax/mocha-bootstrap

+0

+1 per la soluzione del carico di dipendenza requirejs in beforeEach – bennidi

1

Si sta tentando di eseguire i moduli JS progettati per i browser (AMD), ma nel backend potrebbe non funzionare (poiché i moduli vengono caricati in modo commonjs). A causa di questo, si dovrà affrontare due questioni:

  1. definiscono non è definito
  2. 0 test eseguito

Nel browser define saranno definiti. Sarà impostato quando hai bisogno di qualcosa con requirejs. Ma nodejs carica i moduli in modo comune. define in questo caso non è definito. Ma sarà definito quando richiediamo con requirejs!

Ciò significa che ora stiamo richiedendo il codice in modo asincrono e presenta il secondo problema, un problema con l'esecuzione asincrona. https://github.com/mochajs/mocha/issues/362

Ecco un esempio funzionante completo. Guarda che dovevo configurare requirejs (amd) per caricare i moduli, non stiamo usando require (node ​​/ commonjs) per caricare i nostri moduli.

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

}) 

E per il modulo che si desidera verificare:

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

Solo nel caso David's answer non era abbastanza chiaro, ho solo bisogno di aggiungere questo:

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

Verso l'alto del file js in cui utilizzo define, come descritto in Documenti RequireJS ("Building node modules with AMD or RequireJS") e nella stessa cartella aggiungere il pacchetto amdefine:

npm install amdefine 

Questo crea la cartella node_modules con il modulo amdefine all'interno.