javascript 让 requirejs 与 Jasmine 一起工作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16423156/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting requirejs to work with Jasmine
提问by The Sheek Geek
I first want to say that I am new to RequireJS and even newer to Jasmine.
我首先想说我是 RequireJS 的新手,甚至是 Jasmine 的新手。
I am having some issues with the SpecRunner and require JS. I have been following the tutorials of Uzi Kilon and Ben Nadel (along with some others) and they helped some but I am still having some issues.
我在使用 SpecRunner 时遇到了一些问题,需要 JS。我一直在关注 Uzi Kilon 和 Ben Nadel(以及其他一些人)的教程,他们帮助了一些人,但我仍然遇到一些问题。
It seems that, if there is an error that is thrown in the test (I can think of one in particular, a type error) the spec runner html will display. This tells me that I have some issues in the javascript. However, after I fix those error no HTML is displayed anymore. I cannot get the test runner to display at all. Can someone find something wrong with my code that would cause this issue?
似乎,如果在测试中抛出错误(我可以特别想到一个错误,类型错误),spec runner html 将显示。这告诉我我在 javascript 中有一些问题。但是,在我修复这些错误后,不再显示 HTML。 我根本无法显示测试运行程序。有人能发现我的代码有什么问题会导致这个问题吗?
Here is my directory structure:
这是我的目录结构:
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
Here is the SpecRunner (index) HTML:
这是SpecRunner(索引)HTML:
<!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>
Here is the specRunner.js (config)
这是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'
}
}
});
Here is a spec:
这是一个规范:
require(["../lib/jasmine/src/notepad"], function (notepad) {
describe("returns titles", function() {
expect(notepad.noteTitles()).toEqual("");
});
});
The notepad source:
记事本来源:
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;
}
};
});
And the Note source (JIC):
和注释源(JIC):
define(function (){
var note = function(title, content) {
this.title = title;
this.content = content;
};
return note;
});
I have made sure that, as far as the app is concerned, the paths are correct. Once I get this working I can play with configuring that paths so that it isn't so yucky.
我已经确保,就应用程序而言,路径是正确的。一旦我开始工作,我就可以玩配置这些路径,这样它就不会那么令人讨厌了。
采纳答案by The Sheek Geek
I managed to get this working with some trial and error. The main issue was that when you write specs it isn't a require that you want to create, you want to use define:
我设法通过一些试验和错误来解决这个问题。主要问题是,当您编写规范时,它不是您要创建的要求,而是要使用定义:
Original:
原来的:
require(["/lib/jasmine/src/notepad"], function (notepad) {
describe("returns titles", function() {
expect(notepad.noteTitles()).toEqual("pick up the kids get milk");
});
});
Working:
在职的:
define(["lib/jasmine/src/notepad"], function (notepad) {
describe("returns titles", function () {
it("something", function() {
expect(notepad.noteTitles()).toEqual("pick up the kids get milk ");
});
});
});
After doing some research it became clear that, when using RequireJS, Anything that you want the require() to use must be wrapped in a define (seems obvious now I guess). You can see that, in the specRunner.js file, a require is used when executing the tests (therefore the need to "define" the specs.
在做了一些研究之后,很明显,在使用 RequireJS 时,您希望 require() 使用的任何内容都必须包含在定义中(现在我猜这似乎很明显)。您可以看到,在 specRunner.js 文件中,执行测试时使用了一个 require(因此需要“定义”规范。
The other issue is that, when creating specs, the describe() AND the it() are necessary (not just the describe like I had in the posted example).
另一个问题是,在创建规范时,describe() 和 it() 是必要的(不仅仅是像我在发布的示例中那样的描述)。
Original:
原来的:
describe("returns titles", function() {
expect(notepad.noteTitles()).toEqual("pick up the kids get milk");
});
Working:
在职的:
describe("returns titles", function () {
it("something", function() {
expect(notepad.noteTitles()).toEqual("pick up the kids get milk ");
});
});
I also changed around where the test runner exists but this was a refactor and did not change the outcome of the tests.
我还改变了测试运行器所在的位置,但这是一个重构,并没有改变测试的结果。
Again, here are the files and the changed:
同样,这里是文件和更改:
note.js:stayed the same
note.js:保持不变
notepad.js:stayed the same
notepad.js:保持不变
index.html:
索引.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:
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:
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");
});
});
});
回答by Gohn67
Just adding this as an alternate answer for people who are you using Jasmine 2.0 standalone. I believe this can work for Jasmine 1.3 also, but the async syntax is different and kind of ugly.
只需将此添加为您独立使用 Jasmine 2.0 的人的替代答案。我相信这也适用于 Jasmine 1.3,但异步语法不同且有点丑陋。
Here is my modified SpecRunner.html file:
这是我修改后的 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>
Now here is an example spec file:
现在这是一个示例规范文件:
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();
});
});
});
Here is a link the async support section from the Jasmine 2.0 docs: http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
这是 Jasmine 2.0 文档中异步支持部分的链接:http: //jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
回答by TopherBullock
Another option for Jasmine 2.0 standalone is creating a boot.js file and setting it up to run your tests after all of your AMD modules have been loaded.
Jasmine 2.0 独立版的另一个选择是创建一个 boot.js 文件并设置它以在加载所有 AMD 模块后运行您的测试。
The ideal end user case for writing tests in our case was to not have to list out all of our spec files or dependencies in once explicit list, and only have the requirement of declaring your *spec files as AMD modules with dependencies.
在我们的案例中编写测试的理想最终用户案例是不必在一次显式列表中列出我们所有的规范文件或依赖项,并且只需要将您的 *spec 文件声明为具有依赖项的 AMD 模块。
Example ideal spec: spec/javascript/sampleController_spec.js
示例理想规范:spec/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();
});
});
});
Ideally the background behaviour of loading the dependency in and running the specs would be totally opaque to anyone coming on to the project wanting to write tests, and they won't need to do anything other than create a *spec.js file with AMD dependencies.
理想情况下,加载依赖项和运行规范的背景行为对于想要编写测试的项目的任何人来说都是完全不透明的,除了创建具有 AMD 依赖项的 *spec.js 文件外,他们不需要做任何事情.
To get this all working, we created a boot file and configured Jasmine to use it (http://jasmine.github.io/2.0/boot.html), and added some magic to wrap around require to temporarily delay running tests until after we have our deps loaded:
为了让这一切正常工作,我们创建了一个引导文件并配置了 Jasmine 以使用它(http://jasmine.github.io/2.0/boot.html),并添加了一些魔法来包裹 require 以暂时延迟运行测试直到之后我们已经加载了我们的 deps:
Our boot.js' "Execution" section:
我们的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();
}
};
We basically keep our AMD syntax specs in a stack, pop them off, require the modules, execute the callback with our assertions in it, then run Jasmine once everything is done loading in.
我们基本上将我们的 AMD 语法规范保存在一个堆栈中,将它们弹出,要求模块,使用我们的断言执行回调,然后在一切加载完成后运行 Jasmine。
This set up allows us to wait until all of the AMD modules required by our individual tests are loaded, and doesn't break AMD patterns by creating globals. There's a little hackery in the fact that we temporarily override require, and only load our app code using require (our `src_dir:
in jasmine.ymlis empty), but the overall goal here is to reduce the overhead of writing a spec.
这种设置允许我们等待,直到我们的各个测试所需的所有 AMD 模块都加载完毕,并且不会通过创建全局变量来破坏 AMD 模式。事实上,我们暂时覆盖了 require,并且仅使用 require 加载我们的应用程序代码(我们`src_dir:
在jasmine.yml 中为空)这一事实有点小技巧,但这里的总体目标是减少编写规范的开销。
回答by lfender6445
you can use done
in combo with before filters to test asynchronous callbacks:
您可以done
与 before 过滤器结合使用来测试异步回调:
beforeEach(function(done) {
return require(['dist/sem-campaign'], function(campaign) {
module = campaign;
return done();
});
});
回答by cancerbero
This is how I do to run a jasmine spec in a html using AMD/requirejs for all my sources and specs.
这就是我使用 AMD/requirejs 在 html 中运行 jasmine 规范的方法,用于我的所有来源和规范。
This is my index.html file that loads jasmine and then my 'unit test starter' :
这是我的 index.html 文件,它加载了 jasmine,然后是我的“单元测试启动器”:
<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>
and then my UnitTestStarter.js is something like this:
然后我的 UnitTestStarter.js 是这样的:
require.config({
"paths": {
....
});
require(['MySpec.js'], function()
{
jasmine.getEnv().execute();
})