Pregunta

Estoy tratando de entender cómo desarrollar el código JavaScript independiente. Quiero escribir el código Javscript con pruebas y módulos, que se ejecutan desde la línea de comando. Entonces he instalado node.js y npm junto con las bibliotecas requirejs, underscore, y mocha.

Mi estructura de directorio se ve así:

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

dónde src/utils.js es un pequeño módulo que estoy escribiendo, con el siguiente código:

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

});

y test/utils.js es la prueba:

> 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 luego trato de correr desde el directorio de nivel superior (entonces mocha ve el test directorio):

> 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)
    ...

Entonces mis preguntas son:

  • ¿Es esta la forma correcta de estructurar el código?
  • ¿Por qué mi prueba no está funcionando?
  • ¿Cuál es la mejor manera de aprender este tipo de cosas? Estoy teniendo dificultades para encontrar buenos ejemplos con Google.

Gracias...

Lo siento, los resultados publicados momentáneamente del código incorrecto; arreglado ahora

PD: estoy usando requiradores porque también quiero ejecutar este código (o parte de él) desde un navegador, más tarde.

Actualización / solución

Algo que no está en las respuestas a continuación es que necesitaba usar mocha -u tdd para el estilo de prueba anterior. Aquí está la prueba final (que también requiere afirmar) y su 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)
¿Fue útil?

Solución

La razón por la que su prueba no se está ejecutando es porque src/utils.js no es una biblioteca node.js válida.

De acuerdo con la documentación requiradora, para coexistir con Node.js y el CommonJS requiere estándar, debe Agregue un poco de boilerplate a la parte superior de tu src/utils.js Archivo así que requeríajs's define la función está cargada.

Sin embargo, dado que RequestJS fue diseñado para poder requerir un código fuente "clásico" orientado al navegador web, tiendo a usar el siguiente patrón con mis bibliotecas Node.js que también quiero ejecutar en el navegador:

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

// Insert code here

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

Esto tiene la ventaja de no requerir una biblioteca adicional para otros usuarios de Node.js y generalmente funciona bien con RequestJS en el cliente.

Una vez que se ejecute su código en Node.js, puede comenzar a probar. Personalmente, todavía prefiero Expresso sobre Mocha, a pesar de que es el marco de prueba sucesor.

Otros consejos

La documentación de Mocha falta sobre cómo configurar estas cosas, y es desconcertante descubrir debido a todos los trucos de magia que hace debajo del capó.

Encontré las claves para que los archivos del navegador usen requiere.js trabajar en moca bajo el nodo: mocha posee para que los archivos se agregan a sus suites con addFile:

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

Y segundo, usa beforeEach con la devolución de llamada opcional para cargar sus módulos de forma asincrónica:

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

Creé un bootstrap sobre cómo hacer que todo funcione: https://github.com/clubajax/mocha-bootstrap

Está tratando de ejecutar módulos JS diseñados para navegadores (AMD), pero en el backend podría no funcionar (ya que los módulos se cargan de la manera CommonJS). Debido a esto, enfrentarás dos problemas:

  1. definir no está definido
  2. 0 pruebas se ejecutan

En el navegadordefine será definido. Se establecerá cuando necesite algo con Requirjs. Pero NodeJs Cargas de los módulos de la manera común. define en este caso no está definido. ¡Pero se definirá cuando requerimos con Requirjs!

Esto significa que ahora requerimos código de forma asíncrona, y trae el segundo problema, un problema con la ejecución de Async.https://github.com/mochajs/mocha/issues/362

Aquí hay un ejemplo de trabajo completo. Mira que tuve que configurar RequestJS (AMD) para cargar los módulos, no estamos utilizando requerir (nodo/comúnjs) para cargar nuestros módulos.

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

})

Y para el módulo que desea probar:

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

Por si acaso Respuesta de David No estaba lo suficientemente claro, solo necesitaba agregar esto:

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

A la parte superior del archivo js donde uso define, como se describe en los documentos requeridos ("Construir módulos de nodo con AMD o requirirjs") y en la misma carpeta agregue el amdefine paquete:

npm install amdefine

Esto crea el node_modules carpeta con el amdefine módulo dentro.

No uso requirejs Así que no estoy seguro de cómo se ve esa sintaxis, pero esto es lo que hago para ejecutar código tanto dentro node y el browser:

Para las importaciones, determine si estamos ejecutando en el nodo o el navegador:

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

Entonces podemos obtener cualquier dependencia correctamente (ya estarán disponibles si están en el navegador o usamos require):

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

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

Y luego cualquier funcionalidad que deba ser utilizada por otros archivos, la exportamos a root:

root.bar = Bar;

En cuanto a los ejemplos, GitHub es una gran fuente. Simplemente ve y mira el código de tu biblioteca favorita para ver cómo lo hicieron :) Usé mocha Para probar una biblioteca JavaScript que se puede usar tanto en el navegador como en el nodo. El código está disponible en https://github.com/bunkat/later.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top