2012-02-16 10 views
35

Próbuję zrozumieć, jak opracować samodzielny kod JavaScript. Chcę napisać kod Javscript za pomocą testów i modułów, uruchamianych z wiersza poleceń. Zainstalowałem więc node.js i npm wraz z bibliotekami requirejs, underscore i mocha.Dlaczego widzę komunikat "define not defined" podczas uruchamiania testu Mocha z RequireJS?

Moja struktura katalogów wygląda następująco:

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

gdzie src/utils.js jest mały moduł, który piszę, z następującego kodu:

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

}); 

i test/utils.js jest 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); 
     }) 
    }) 

}); 

którą następnie próbuję uruchomić z katalogu najwyższego poziomu (tak mocha widzi katalog 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) 
    ... 

Więc moje pytania to:

  • Czy to poprawny sposób struktura kodu?
  • Dlaczego mój test nie działa?
  • Jaki jest najlepszy sposób na naukę tego typu rzeczy? Mam trudności ze znalezieniem dobrych przykładów w Google.

Dzięki ...

[przepraszam - chwilowo pisał wyniki niewłaściwym kodem; naprawiono teraz]

PS Używam requirejs, ponieważ chcę również uruchomić ten kod (lub jego część) z przeglądarki, później.

Aktualizacja/Rozwiązanie

coś, co nie jest w poniższych odpowiedzi jest to, że potrzebne do korzystania mocha -u tdd dla stylu testowej powyżej. Oto test końcowy (który wymaga również assert) i jego zastosowanie:

> 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

Dla mnie, aby to działało, potrzebuję zainstalować moduł amdefine i dodać ten wiersz coffeescript = >> define = require ('amdefine') (moduł) if (typeof define! = 'Function') << = into mój plik "klasy", aby działał (nie plik testowy). Jest to trochę denerwujące, ponieważ trzeba mieć zadanie, aby usunąć to po przetestowaniu – devric

Odpowiedz

15

Powodem, dla którego test nie jest uruchomiony, jest to, że src/utils.js nie jest prawidłową biblioteką Node.js.

Zgodnie z dokumentacją RequireJS, aby współistnieć z node.js i CommonJS wymagają standardy, trzeba add a bit of boilerplate do początku pliku src/utils.js tak define funkcja RequireJS jest załadowany.

Jednak od RequireJS został zaprojektowany, aby być w stanie wymagać „Classic” kodu źródłowego przeglądarki internetowej zorientowanych, staram się używać poniższego wzoru z moich bibliotek node.js, że ja też chcę działa w przeglądarce:

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

// Insert code here 

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

Ma to tę zaletę, że nie wymaga dodatkowej biblioteki dla innych użytkowników Node.js i ogólnie działa dobrze z RequireJS na kliencie.

Po uruchomieniu kodu w Node.js można rozpocząć testowanie. Osobiście wciąż wolę expresso od mokki, mimo że jest to następna struktura testowa.

+1

dzięki! nie sądzę, że wiedziałbyś również, co muszę zrobić, aby "suite" (z mokki) został zdefiniowany, ponieważ z płytką wzorcową mój test kończy się niepowodzeniem? także, czy mówisz, że "define" nie będzie działać dla kodu przeglądarki? nie rozumiem twojej motywacji do alternatywnego podejścia powyżej - czy jest to "tylko" kwestia stylu? –

+0

ah, widzę twój punkt - nie chcesz definiować elementów węzła dla przeglądarek internetowych. –

+0

To nie jest trudne, brakuje ci "' require ('mocha') ''. [Podjęty prosto z końskiego ujścia] (https://github.com/visionmedia/mocha/blob/master/test/suite.js) jest odpowiedzią. (Jestem nowy w StackOverflow, nie wiedziałem, że nie możesz mieć kodu źródłowego wielowierszowego w komentarzach.) –

-1

nie używam requirejs więc nie jestem pewien, co to składnia wygląda, ale to, co zrobić, aby uruchomić kod zarówno w ciągu node a browser:

Dla importu, określić, czy prowadzimy w węźle lub przeglądarka:

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

Wtedy możemy chwycić wszelkie zależności poprawnie (będzie to albo być już dostępna, jeśli w przeglądarce lub używamy require):

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

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

A potem każdy funkcjonalność, która musi być używany w innych plikach, eksportujemy je do korzeni:

root.bar = Bar; 

Jako przykłady, GitHub jest doskonałym źródłem.Po prostu idź i sprawdź kod ulubionej biblioteki, aby zobaczyć, jak to zrobili :) Użyłem mocha do przetestowania biblioteki javascript, która może być używana zarówno w przeglądarce, jak i w węźle. Kod jest dostępny pod adresem https://github.com/bunkat/later.

4

Brakuje dokumentacji Mocha, jak ustawić te rzeczy, i to jest kłopotliwe, aby dowiedzieć się z powodu wszystkich magicznych sztuczek, które wykonuje pod maską.

znalazłam klucze do pobierania plików za pomocą przeglądarki require.js do pracy w ramach Węzła Mocha: Mocha ma mieć pliki dodane do swoich apartamentów z addFile:

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

a po drugie, używać beforeEach z opcjonalnym zwrotnego załadować moduły asynchronicznie:

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

stworzyłem bootstrap jak uzyskać ten wszystko działa: https://github.com/clubajax/mocha-bootstrap

+0

+1 za rozwiązanie zależności dependjs ładowanie w beforeEach – bennidi

1

Próbujesz uruchomić moduły JS przeznaczone dla przeglądarek (AMD), ale w zapleczu może nie działać (ponieważ moduły są ładowane metodą commonjs). Z tego powodu, będziesz musiał stawić czoła dwie kwestie:

  1. określenie nie jest zdefiniowana
  2. 0 testy uruchomić

w przeglądarce define zostanie zdefiniowany. Zostanie on ustawiony, gdy będziesz potrzebować czegoś z requirejs. Ale nodejs ładuje moduły metodą commonjs. define w tym przypadku nie jest zdefiniowany. Ale zostanie to zdefiniowane, gdy wymagamy od requirejs!

Oznacza to, że teraz wymagamy asynchronicznego kodu, a to przynosi drugi problem, problem z wykonywaniem asynchronizacji. https://github.com/mochajs/mocha/issues/362

Oto pełny przykład pracy. Wygląda na to, że musiałem skonfigurować requirejs (amd), aby załadować moduły, nie używamy require (node ​​/ commonjs) do ładowania naszych modułów.

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

}) 

A dla modułu, który chcesz przetestować:

> 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

wszelki wypadek David's answer nie było wystarczająco jasne, po prostu potrzebne, aby dodać to:

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

Do góry pliku js, w którym używam define, jak opisano w dokumentacji RequireJS ("Building node modules with AMD or RequireJS") iw tym samym folderze dodaj pakiet amdefine:

npm install amdefine 

Spowoduje to utworzenie folderu node_modules z modułem amdefine w środku.

Powiązane problemy