2013-05-07 2 views
63

Прежде всего хочу сказать, что я новичок в RequireJS и даже новичок в Jasmine.Получение требований к работе с Jasmine

У меня возникли некоторые проблемы с SpecRunner и требуется JS. Я слежу за учебниками Узи Килона и Бена Наделя (наряду с некоторыми другими), и они помогли некоторым, но у меня все еще есть некоторые проблемы.

Похоже, что если в тесте возникла ошибка (я могу вспомнить, в частности, ошибку типа), отобразится spec runner html. Это говорит мне, что у меня есть некоторые проблемы в javascript. Однако после исправления этих ошибок HTML больше не отображается. Я не могу запустить тестовый бегун. Может кто-то найти что-то не так с моим кодом, что вызовет эту проблему?

Вот моя структура каталог:

Root 
|-> lib 
    |-> jasmine 
     |-> lib (contains all of the jasmine lib) 
     |-> spec 
     |-> src 
    |-> jquery (jquery js file) 
    |-> require (require js file) 
index.html (spec runner) specRunner.js 

Здесь (индекс) HTML SpecRunner:

<!doctype html> 
<html lang="en"> 
    <head> 
     <title>Javascript Tests</title> 

     <link rel="stylesheet" href="lib/jasmine/lib/jasmine.css"> 

     <script src="lib/jasmine/lib/jasmine.js"></script> 
     <script src="lib/jasmine/lib/jasmine-html.js"></script> 
     <script src="lib/jquery/jquery.js"></script> 
     <script data-main="specRunner" src="lib/require/require.js"></script> 

     <script> 
      require({ paths: { spec: "lib/jasmine/spec" } }, [ 
        // Pull in all your modules containing unit tests here. 
        "spec/notepadSpec" 
       ], function() { 
        jasmine.getEnv().addReporter(new jasmine.HtmlReporter()); 
        jasmine.getEnv().execute(); 
       }); 
     </script> 

    </head> 

<body> 
</body> 
</html> 

Вот specRunner.js (конфигурации)

require.config({ 
    urlArgs: 'cb=' + Math.random(), 
    paths: { 
     jquery: 'lib/jquery', 
     jasmine: 'lib/jasmine/lib/jasmine', 
     'jasmine-html': 'lib/jasmine/lib/jasmine-html', 
     spec: 'lib/jasmine/spec/' 
    }, 
    shim: { 
     jasmine: { 
      exports: 'jasmine' 
     }, 
     'jasmine-html': { 
      deps: ['jasmine'], 
      exports: 'jasmine' 
     } 
    } 
}); 

Вот спецификации:

require(["../lib/jasmine/src/notepad"], function (notepad) { 
    describe("returns titles", function() { 
     expect(notepad.noteTitles()).toEqual(""); 


    }); 
}); 

Источник блокнота:

define(['lib/jasmine/src/note'], function (note) { 

    var notes = [ 
     new note('pick up the kids', 'dont forget to pick up the kids'), 
     new note('get milk', 'we need two gallons of milk') 
    ]; 


    return { 
     noteTitles: function() { 
      var val; 

      for (var i = 0, ii = notes.length; i < ii; i++) { 
       //alert(notes[i].title); 
       val += notes[i].title + ' '; 
      } 

      return val; 
     } 
    }; 
}); 

И источник Примечание (СИК):

define(function(){ 
    var note = function(title, content) { 
     this.title = title; 
     this.content = content; 
    }; 

    return note; 
}); 

Я убедился, что, насколько приложение обеспокоено, пути верны. Как только я получу эту работу, я могу играть с настройкой этих путей, чтобы она не была такой яркой.

+0

Не могли бы вы попробовать это? Определено HtmlReported вне запроса. Вызов выполняется только внутри. var jasmineEnv = jasmine.getEnv(); jasmineEnv.addReporter (новый jasmine.HtmlReporter()); require (['suites/aSpec.js'], function (spec) { jasmineEnv.execute(); }); – basos

+1

Для Jasmine 2.0.0, этот ответ работал для меня: http://stackoverflow.com/questions/19240302/does-jasmine-2-0-really-not-work-with-require-js/20851265#20851265 – shaunsantacruz

ответ

55

Мне удалось получить эту работу с некоторыми проб и ошибок. Основной вопрос заключается в том, что когда вы пишете спецификации это не требуется, что вы хотите создать, вы хотите использовать определение:

Оригинала:

require(["/lib/jasmine/src/notepad"], function (notepad) { 
    describe("returns titles", function() { 
     expect(notepad.noteTitles()).toEqual("pick up the kids get milk"); 


    }); 
}); 

Рабочие:

define(["lib/jasmine/src/notepad"], function (notepad) { 
    describe("returns titles", function() { 

     it("something", function() { 

      expect(notepad.noteTitles()).toEqual("pick up the kids get milk "); 
     }); 

    }); 
}); 

После нескольких исследований выяснилось, что при использовании RequireJS все, что вы хотите, чтобы require() использовать, должно быть завернуто в определение (кажется, теперь я думаю). Вы можете видеть, что в файле specRunner.js при выполнении тестов используется требование (поэтому необходимо «определить» спецификации.

Другая проблема заключается в том, что при создании спецификаций описание() AND он() необходим (не просто описать, как в опубликованном примере).

Оригинал:

describe("returns titles", function() { 
     expect(notepad.noteTitles()).toEqual("pick up the kids get milk"); 


    }); 

Рабочая:

describe("returns titles", function() { 

     it("something", function() { 

      expect(notepad.noteTitles()).toEqual("pick up the kids get milk "); 
     }); 

    }); 

Я также изменил вокруг, где тест бегун существует, но это было рефакторинг и не изменили исход испытаний.

Опять же, здесь файлы и измененные:

note.js: остались те же

notepad.js: остались прежними

index.html:

<!doctype html> 
<html lang="en"> 
    <head> 
     <title>Javascript Tests</title> 
     <link rel="stylesheet" href="lib/jasmine/lib/jasmine.css"> 
     <script data-main="specRunner" src="lib/require/require.js"></script> 
    </head> 

    <body> 
    </body> 
</html> 

specRunner.js:

require.config({ 
    urlArgs: 'cb=' + Math.random(), 
    paths: { 
     jquery: 'lib/jquery', 
     'jasmine': 'lib/jasmine/lib/jasmine', 
     'jasmine-html': 'lib/jasmine/lib/jasmine-html', 
     spec: 'lib/jasmine/spec/' 
    }, 
    shim: { 
     jasmine: { 
      exports: 'jasmine' 
     }, 
     'jasmine-html': { 
      deps: ['jasmine'], 
      exports: 'jasmine' 
     } 
    } 
}); 


require(['jquery', 'jasmine-html'], function ($, jasmine) { 

    var jasmineEnv = jasmine.getEnv(); 
    jasmineEnv.updateInterval = 1000; 

    var htmlReporter = new jasmine.HtmlReporter(); 

    jasmineEnv.addReporter(htmlReporter); 

    jasmineEnv.specFilter = function (spec) { 
     return htmlReporter.specFilter(spec); 
    }; 

    var specs = []; 

    specs.push('lib/jasmine/spec/notepadSpec'); 



    $(function() { 
     require(specs, function (spec) { 
      jasmineEnv.execute(); 
     }); 
    }); 

}); 

notepadSpec.js:

define(["lib/jasmine/src/notepad"], function (notepad) { 
    describe("returns titles", function() { 

     it("something", function() { 

      expect(notepad.noteTitles()).toEqual("pick up the kids get milk"); 
     }); 

    }); 
}); 
+1

+1 для _ Основная проблема заключалась в том, что когда вы пишете спецификации, это не требуется, что вы хотите создать, вы хотите использовать define_. Если вы используете require, ваши тесты будут иногда работать, а иногда не с ошибкой _no specs found_. –

12

Просто добавить это как альтернативный ответ для людей, которые вы используете жасмин 2.0 автономно. Я считаю, что это также может работать и для Jasmine 1.3, но асинхронный синтаксис отличается от своего рода уродливым.

Вот мой модифицированный файл SpecRunner.html:

<!DOCTYPE HTML> 
<html> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <title>Jasmine Spec Runner v2.0.0</title> 

    <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.0.0/jasmine_favicon.png"> 
    <link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.0/jasmine.css"> 

    <!-- 
    Notice that I just load Jasmine normally 
    -->  
    <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine.js"></script> 
    <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine-html.js"></script> 
    <script type="text/javascript" src="lib/jasmine-2.0.0/boot.js"></script> 

    <!-- 
    Here we load require.js but we do not use data-main. Instead we will load the 
    the specs separately. In short we need to load the spec files synchronously for this 
    to work. 
    --> 
    <script type="text/javascript" src="js/vendor/require.min.js"></script> 

    <!-- 
    I put my require js config inline for simplicity 
    --> 
    <script type="text/javascript"> 
    require.config({ 
     baseUrl: 'js', 
     shim: { 
      'underscore': { 
       exports: '_' 
      }, 
      'react': { 
       exports: 'React' 
      } 
     }, 
     paths: { 
      jquery: 'vendor/jquery.min', 
      underscore: 'vendor/underscore.min', 
      react: 'vendor/react.min' 
     } 
    }); 
    </script> 

    <!-- 
    I put my spec files here 
    --> 
    <script type="text/javascript" src="spec/a-spec.js"></script> 
    <script type="text/javascript" src="spec/some-other-spec.js"></script> 
</head> 

<body> 
</body> 
</html> 

Теперь вот пример спецификации файла:

describe("Circular List Operation", function() { 

    // The CircularList object needs to be loaded by RequireJs 
    // before we can use it. 
    var CircularList; 

    // require.js loads scripts asynchronously, so we can use 
    // Jasmine 2.0's async support. Basically it entails calling 
    // the done function once require js finishes loading our asset. 
    // 
    // Here I put the require in the beforeEach function to make sure the 
    // Circular list object is loaded each time. 
    beforeEach(function(done) { 
     require(['lib/util'], function(util) { 
      CircularList = util.CircularList; 
      done(); 
     }); 
    }); 

    it("should know if list is empty", function() { 
     var list = new CircularList(); 
     expect(list.isEmpty()).toBe(true); 
    }); 

    // We can also use the async feature on the it function 
    // to require assets for a specific test. 
    it("should know if list is not empty", function(done) { 
     require(['lib/entity'], function(entity) { 
      var list = new CircularList([new entity.Cat()]); 
      expect(list.isEmpty()).toBe(false); 
      done(); 
     }); 
    }); 
}); 

Вот ссылка в раздел поддержки асинхронной из документации жасмин 2.0: http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support

+0

Стоит отметить, что это единственное найденное решение, которое работает с [node-webkit] (https://github.com/rogerwang/node-webkit) в сочетании с плагином [RequireJS r.js] (http://requirejs.org/docs/1.0/docs/node.html), чтобы я мог проверить свой код, который импортирует модули AMD и Node.js. – jmort253

+0

ваши спецификации не используют amd, и я думаю, что это целая цель этого вопроса. – cancerbero

3

Другой вариант автономного Jasmine 2.0 - создать файл boot.js и настроить его для запуска тестов после загрузки всех модулей AMD.

Идеальный случай для конечных пользователей для написания тестов в нашем случае состоял в том, что нам не нужно было перечислять все наши файлы спецификаций или зависимости в некотором явном списке и иметь только требование объявлять ваши * spec-файлы как модули AMD с зависимостями ,

Пример идеальная спецификация: спецификация/JavaScript/sampleController_spec.js

require(['app/controllers/SampleController'], function(SampleController) { 
    describe('SampleController', function() { 
     it('should construct an instance of a SampleController', function() { 
     expect(new SampleController() instanceof SampleController).toBeTruthy(); 
     }); 
    }); 
}); 

В идеале фон поведение загрузки зависимости в и запуске спецификации будет полностью непрозрачна для любых приходить на проект, желающий пишите тесты, и им не нужно ничего делать, кроме создания файла * spec.js с зависимостями AMD.

Чтобы получить все это работает, мы создали загрузочный файл и настроен жасмин, чтобы использовать его (http://jasmine.github.io/2.0/boot.html), и добавили немного магии, чтобы обернуть вокруг требуем, чтобы временно отложить выполнение тестов, пока у нас есть наши Deps загружены:

Наш "раздел boot.js„Исполнение“:

/** 
* ## Execution 
* 
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. 
*/ 

var currentWindowOnload = window.onload; 

// Stack of AMD spec definitions 
var specDefinitions = []; 

// Store a ref to the current require function 
window.oldRequire = require; 

// Shim in our Jasmine spec require helper, which will queue up all of the definitions to be loaded in later. 
require = function(deps, specCallback){ 
    //push any module defined using require([deps], callback) onto the specDefinitions stack. 
    specDefinitions.push({ 'deps' : deps, 'specCallback' : specCallback }); 
}; 

// 
window.onload = function() { 

    // Restore original require functionality 
    window.require = oldRequire; 
    // Keep a ref to Jasmine context for when we execute later 
    var context = this, 
     requireCalls = 0, // counter of (successful) require callbacks 
     specCount = specDefinitions.length; // # of AMD specs we're expecting to load 

    // func to execute the AMD callbacks for our test specs once requireJS has finished loading our deps 
    function execSpecDefinitions() { 
    //exec the callback of our AMD defined test spec, passing in the returned modules. 
    this.specCallback.apply(context, arguments);   
    requireCalls++; // inc our counter for successful AMD callbacks. 
    if(requireCalls === specCount){ 
     //do the normal Jamsine HTML reporter initialization 
     htmlReporter.initialize.call(context); 
     //execute our Jasmine Env, now that all of our dependencies are loaded and our specs are defined. 
     env.execute.call(context); 
    } 
    } 

    var specDefinition; 
    // iterate through all of our AMD specs and call require with our spec execution callback 
    for (var i = specDefinitions.length - 1; i >= 0; i--) { 
    require(specDefinitions[i].deps, execSpecDefinitions.bind(specDefinitions[i])); 
    } 

    //keep original onload in case we set one in the HTML 
    if (currentWindowOnload) { 
    currentWindowOnload(); 
    } 

}; 

Мы в основном сохранить наши синтаксические функции AMD в стеке, поп их, требуют модулей, выполнить обратный вызов с нашими утверждениями в нем, а затем запустить Жасмин как только все будет загружено.

Эта настройка позволяет подождать до тех пор, пока все модули AMD, необходимые для наших индивидуальных тестов, не будут загружены и не разрушат шаблоны AMD, создавая глобальные переменные. Есть немного хакерства в том, что мы временно переопределяем требуем, и загружаем только наш код приложения, используя require (наш `src_dir: в jasmine.yml пуст), но общая цель здесь - уменьшить накладные расходы на написание спецификации.

+0

Отличный ответ, если вы используете Jasmine 2.0. Работал как шарм .. – mehrandvd

3

вы можете использовать done в комбо с фильтрами, прежде чем тестировать асинхронные обратные вызовы:

beforeEach(function(done) { 
    return require(['dist/sem-campaign'], function(campaign) { 
     module = campaign; 
     return done(); 
    }); 
    }); 
1

Это, как мне сделать, чтобы запустить спецификацию жасмин в HTML с помощью AMD/requirejs для всех моих источников и спецификаций.

Это мой index.html файл, который загружает жасмин, а затем мой «модульного тестирования стартера»:

<html><head><title>unit test</title><head> 
<link rel="shortcut icon" type="image/png" href="/jasmine/lib/jasmine-2.1.3/jasmine_favicon.png"> 
<link rel="stylesheet" href="/jasmine/lib/jasmine-2.1.3/jasmine.css"> 
<script src="/jasmine/lib/jasmine-2.1.3/jasmine.js"></script> 
<script src="/jasmine/lib/jasmine-2.1.3/jasmine-html.js"></script> 
<script src="/jasmine/lib/jasmine-2.1.3/boot.js"></script> 
</head><body> 
<script data-main="javascript/UnitTestStarter.js" src="javascript/require.js"></script> 
</body></html> 

и тогда мои UnitTestStarter.js что-то вроде этого:

require.config({ 
    "paths": { 
     .... 
}); 
require(['MySpec.js'], function() 
{ 
    jasmine.getEnv().execute(); 
}) 
Смежные вопросы