Perché vedo “Definisci non definito” quando si esegue un test di Mocha con RequireJS?
-
25-10-2019 - |
Domanda
Sto cercando di capire come sviluppare codice Javascript stand-alone. Voglio scrivere il codice javscript con i test e moduli, che va dalla linea di comando. Così ho installato node.js
e npm
insieme con le librerie requirejs
, underscore
e mocha
.
Il mio Directory struttura si presenta come 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
è la prova:
> 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 ho poi tenta di eseguire dalla directory di livello superiore (in modo 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 le seguenti:
- E 'questo il modo corretto per il codice struttura?
- Perché il mio test non correre?
- Qual è il modo migliore per imparare questo genere di cose? Sto avendo difficoltà a trovare buoni esempi con Google.
Grazie ...
[dispiace - risultati momentaneamente postato da codice errato; Ora riparato]
PS Sto usando requirejs perché voglio anche eseguire questo codice (o parte di esso) da un browser, più tardi.
Aggiornamento / Soluzione
Una cosa che non è nelle risposte qui di seguito è 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)
Soluzione
Il motivo per il test non è in esecuzione è perché src/utils.js
non è una libreria Node.js valido.
Secondo la documentazione RequireJS, al fine di coesistere con Node.js ei CommonJS richiedono standard è necessario aggiungere un po 'di boilerplate alla parte superiore del file in modo src/utils.js
funzione define
delle RequireJS 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 i miei Node.JS librerie 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 in più per gli altri utenti Node.js e generalmente funziona bene con RequireJS sul client.
Una volta che il codice in esecuzione in Node.js, è possibile avviare il test. Io personalmente preferisco ancora espresso nel corso moka, anche se il suo quadro di prova successore.
Altri suggerimenti
La documentazione Mocha è carente su come impostare questa roba, e si perplessi di capire a causa di tutti i trucchi di magia lo fa sotto il cofano.
Ho trovato le chiavi per ottenere file del browser utilizzando require.js al lavoro in Mocha sotto Node: Mocha ha di avere i file aggiunti alle sue suite con addFile
:
mocha.addFile('lib/tests/Main_spec_node');
E in secondo luogo, l'uso 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 tutto questo lavoro: https://github.com/clubajax/mocha-bootstrap
Si sta cercando di eseguire moduli JS progettati per browser (AMD), ma nel backend potrebbe non funzionare (come moduli vengono caricati il ??modo commonjs). A causa di questo, si dovrà affrontare due questioni:
- Definisci non è definito
- 0 test eseguire
Nel browserdefine
sarà definito. Esso sarà impostato quando si richiede qualcosa con requirejs. Ma nodejs carica i moduli il modo commonjs. define
in questo caso non è definito. Ma sarà definito quando abbiamo bisogno con requirejs!
Questo significa che ora stiamo richiedere codice in modo asincrono, e porta il secondo problema, un problema con l'esecuzione asincrona. https://github.com/mochajs/mocha/issues/362
Ecco un esempio di lavoro completo. Guardate che ho dovuto requirejs configure (AMD) per caricare i moduli, non stiamo usando richiedere (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();
})
Nel caso in cui risposta di David non era abbastanza chiaro, ho solo bisogno di aggiungere questo:
if (typeof define !== 'function') {
var define = require('amdefine')(module);
}
Per la parte superiore del file js in cui io uso define
, come descritto in RequireJS docs (" Creazione di moduli nodi con AMD o RequireJS ") e nella stessa cartella aggiungere il pacchetto amdefine
:
npm install amdefine
Questo crea la cartella node_modules
con l'interno del modulo amdefine
.
Non faccio uso di requirejs
quindi non sono sicuro di quello che sembra sintassi del tipo, ma questo è quello che faccio per eseguire codice sia all'interno node
e browser
:
Per le importazioni, a determinare se ci sono in esecuzione nel nodo o il browser:
var root = typeof exports !== "undefined" && exports !== null ? exports : window;
Poi possiamo afferrare qualsiasi 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 devono essere utilizzati da altri file, esportiamo a radice:
root.bar = Bar;
Per quanto riguarda gli esempi, GitHub
è una grande fonte. Basta andare a controllare il codice per la libreria preferita per vedere come hanno fatto :) Ho usato mocha
per testare una libreria JavaScript che può essere utilizzato sia nel browser e nodo. Il codice è disponibile presso https://github.com/bunkat/later .