如何在 javascript 认为文档“准备好”之前加载我的 jasmine 测试装置?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12715207/
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
How can I get my jasmine tests fixtures to load before the javascript considers the document to be "ready"?
提问by Rebekah Waterbury
I am fairly certain that the issue is that the jquery bindings set to run on $(document).ready do not have the fixture html available to them. So when my events occur that are intended to make a change to the DOM via a jquery function, nothing happens, and my tests fail. I saw a "solution" to this problem here, but that solution which did work for me, required changing my working jquery function to bind with the .live method instead of the .click method. I have two issue with this. First I do not want to have to change my working code so that the tests will pass properly. The testing framework ought to test whether the code will work in the app, where the DOM load and the javascript bindings occur in the correct order. The second issue I have with the solution is that .on and .delegate both did not work for some reason and the only thing that ended up working was to use the .live method which is currently in the process of being deprecated. In conclusion, I would like to figure out how to change either my tests or the testing framework itself, such that the fixtures are loaded before the functions that run in $(document).ready.
我相当确定问题在于设置为在 $(document).ready 上运行的 jquery 绑定没有可用的夹具 html。因此,当我打算通过 jquery 函数更改 DOM 的事件发生时,没有任何反应,并且我的测试失败。我在这里看到了这个问题的“解决方案”,但是那个对我有用的解决方案需要更改我的工作 jquery 函数以绑定 .live 方法而不是 .click 方法。我有两个问题。首先,我不想更改我的工作代码以便测试正确通过。测试框架应该测试代码是否可以在应用程序中工作,其中 DOM 加载和 javascript 绑定以正确的顺序发生。我在解决方案中遇到的第二个问题是 .on 和 .delegate 由于某种原因都不起作用,而最终起作用的唯一方法是使用目前正在弃用的 .live 方法。总之,我想弄清楚如何更改我的测试或测试框架本身,以便在 $(document).ready 中运行的函数之前加载夹具。
I am working with rails 3.2.8 and I have two different branches set up to experiment with jasmine testing. One of the branches uses the jasminerice gem and the other uses the jasmine-rails gem. The Javascript and jQuery(when using the .live method) tests all pass properly in both of these set-ups.
我正在使用 rails 3.2.8,我设置了两个不同的分支来试验茉莉花测试。其中一个分支使用 jasminerice gem,另一个分支使用 jasmine-rails gem。Javascript 和 jQuery(使用 .live 方法时)测试在这两种设置中都正确通过。
Here is a description of the branch using jasminerice:
这是使用 jasminerice 的分支的描述:
Here are the lines from my Gemfile.lock file describing the jasmine and jQuery set-up:
以下是我的 Gemfile.lock 文件中描述 jasmine 和 jQuery 设置的行:
jasminerice (0.0.9)
coffee-rails
haml
jquery-rails (2.1.3)
railties (>= 3.1.0, < 5.0)
thor (~> 0.14)
Jasminerice includes the jasmine-jqueryextension by default. The jasmine-jQuery extension provides the toHaveText method I am using in the tests.
Jasminerice 默认包含jasmine-jquery扩展。jasmine-jQuery 扩展提供了我在测试中使用的 toHaveText 方法。
The test file jasmine_jquery_test.js which is located directly within the spec/javascripts directory contains this content:
直接位于 spec/javascripts 目录中的测试文件 jasmine_jquery_test.js 包含以下内容:
#= require application
describe ("my basic jasmine jquery test", function(){
beforeEach(function(){
$('<a id="test_link" href="somewhere.html">My test link</a>').appendTo('body');
});
afterEach(function(){
$('a#test_link').remove();
});
it ("does some basic jQuery thing", function () {
$('a#test_link').click();
expect($("a#test_link")).toHaveText('My test link is now longer');
});
it ("does some the same basic jQuery thing with a different trigger type", function () {
$('a#test_link').trigger('click');
expect($("a#test_link")).toHaveText('My test link is now longer');
});
});
describe ('subtraction', function(){
var a = 1;
var b = 2;
it("returns the correct answer", function(){
expect(subtraction(a,b)).toBe(-1);
});
});
My javascript file tests.js which is located in the app/assets/javascripts dir has this content:
我的 javascript 文件 tests.js 位于 app/assets/javascripts 目录中有以下内容:
function subtraction(a,b){
return a - b;
}
jQuery (function($) {
/*
The function I would rather use -
$("a#test_link").click(changeTheTextOfTheLink)
function changeTheTextOfTheLink(e) {
e.preventDefault()
$("a#test_link").append(' is now longer');
}
*/
$("a#test_link").live('click', function(e) {
e.preventDefault();
$("a#test_link").append(' is now longer');
});
});
My application.js file located in the same app/assets/javascripts dir has this content:
我的 application.js 文件位于同一个 app/assets/javascripts 目录中有以下内容:
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require vendor
//= require_tree .
And the description of the jasmine-rails branch can be found in the content of my first jasmine test related stackoverflow question.
并且jasmine-rails分支的描述可以在我的第一个jasmine测试相关的stackoverflow问题的内容中找到。
So if anyone has an idea how to manipulate the tests such that the $(document).ready functions are run after the fixtures are loaded I would very much like to hear your thoughts?
因此,如果有人知道如何操作测试,以便在加载装置后运行 $(document).ready 函数,我非常想听听您的想法?
采纳答案by Rebekah Waterbury
Adding the jQuery directly to the html fixture worked for me to get the desired behavior. It is not exactly an answer to this question, but I am starting to believe it's the best solution currently available. My changes where made in the jasmine-rails gem set-up and I haven't yet tried it in the jasminerice branch.
将 jQuery 直接添加到 html 固定装置为我工作以获得所需的行为。这并不完全是这个问题的答案,但我开始相信这是目前可用的最佳解决方案。我在 jasmine-rails gem 设置中所做的更改,我还没有在 jasminerice 分支中尝试过。
Here is my test file:
这是我的测试文件:
describe ("my basic jasmine jquery test", function(){
beforeEach(function(){
loadFixtures('myfixture.html');
});
it ("does some basic jQuery thing", function () {
$('a#test_link').click();
expect($("a#test_link")).toHaveText('My test link is now longer');
});
it ("does the same basic jQuery thing with a different event initiation method", function () {
$('a#test_link').trigger('click');
expect($("a#test_link")).toHaveText('My test link is now longer');
});
});
describe ('substraction', function(){
var a = 1;
var b = 2;
it("returns the correct answer", function(){
expect(substraction(a,b)).toBe(-1);
});
});
And here is my fixture file:
这是我的夹具文件:
<a id="test_link" href="somewhere.html">My test link</a>
<script>
$("a#test_link").click(changeTheTextOfTheLink)
function changeTheTextOfTheLink(e) {
e.preventDefault()
$("a#test_link").append(' is now longer');
}
</script>
回答by LeeGee
Have you tried jasmine-jquery?
你试过 jasmine-jquery 吗?
https://github.com/velesin/jasmine-jquery
https://github.com/velesin/jasmine-jquery
From it's github page,
从它的github页面,
jasmine-jquery provides two extensions for Jasmine JavaScript Testing Framework:
a set of custom matchers for jQuery framework an API for handling HTML, CSS, and JSON fixtures in your specs
jasmine-jquery 为 Jasmine JavaScript 测试框架提供了两个扩展:
一组用于 jQuery 框架的自定义匹配器 一个用于处理规范中的 HTML、CSS 和 JSON 固定装置的 API
回答by Yunzhou
I used dom_mungerto automatically generate the fixture for me, so adding the jquery code manually inside the fixture isn't an option for me. I've been searching for the same answer, and the best solution I can think of right now is to use event delegate in jQuery.
我使用dom_munger为我自动生成夹具,因此在夹具中手动添加 jquery 代码对我来说不是一个选择。我一直在寻找相同的答案,我现在能想到的最佳解决方案是在 jQuery 中使用事件委托。
For example, instead of writing this:
例如,而不是这样写:
$('#target').click(function(){
// Do work
});
Do this:
做这个:
$(document).on('click', '#target', function(){
// Do work
});
In this way, the listener is attached to the document, which is present before the fixture is loaded. So when the click event happens on #target, it bubbles up to document. Document checks if the origin matches the second argument - '#target'. If it matches, the handler function will be called.
通过这种方式,侦听器附加到文档,该文档在加载夹具之前就已存在。所以当点击事件发生在#target 上时,它会冒泡到文档中。文档检查源是否匹配第二个参数 - '#target'。如果匹配,将调用处理程序函数。
I know there are limitations to this, such as initializing plug-ins, but it does solve part of the problem.
我知道这有一些限制,例如初始化插件,但它确实解决了部分问题。
回答by Darius
I took a slightly different approach to those described here to solve this limitation.
我采用了与此处描述的方法略有不同的方法来解决此限制。
Disclaimer: I work for Microsoft so I cannot post my actual source code here without legal approval, so instead I'll just describe an approach that works well.
免责声明:我为 Microsoft 工作,因此未经法律批准我不能在此处发布我的实际源代码,因此我将仅描述一种有效的方法。
Rather than trying to change how document.ready
works, I modified the jasmine-jquery source to support a function called fixturesReady
that takes a callback.
document.ready
我没有尝试改变工作方式,而是修改了 jasmine-jquery 源代码以支持一个fixturesReady
需要回调的函数。
Essentially this is defined inside an IIFE, and holds an array of callbacks per event name privately, that are iterated over on trigger.
本质上,这是在 IIFE 中定义的,并私下保存每个事件名称的回调数组,这些回调在触发器上迭代。
Then on this chunk you can put the trigger:
然后在这个块上你可以放置触发器:
jasmine.Fixtures.prototype.load = function() {
this.cleanUp()
this.createContainer_(this.read.apply(this, arguments))
fixturesReady.trigger("loaded", arguments); // <----- ADD THIS
}
So in your tests now you can code against:
因此,现在在您的测试中,您可以针对以下内容进行编码:
fixturesReady(yourCallback)
And you know that when yourCallback
is invoked you can safely query the DOM for your fixture elements.
并且您知道何时yourCallback
调用您可以安全地查询 DOM 以获取您的夹具元素。
Additionally, if you're using the async.beforeEach
jasmine plugin you could do this:
此外,如果您使用async.beforeEach
jasmine 插件,您可以这样做:
async.beforeEach(function(done){
fixturesReady(done);
...
loadFixtures("....");
});
Hope that helps, and serves to give you some ideas about solving this problem.
希望有所帮助,并为您提供一些解决此问题的想法。
NOTE: Remember in your plugin to clear any callbacks in an afterEach
block if necessary :)
注意:afterEach
如有必要,请记住在您的插件中清除块中的任何回调:)
回答by Nicholas Murray
It has been a while since this question was asked (and an answer accepted).
自从提出这个问题以来已经有一段时间了(并接受了答案)。
Here is a better approach to structure your test and load the script for testing with jasmine.
这是构建测试并加载脚本以使用 jasmine 进行测试的更好方法。
templates/link.tmpl.html
模板/link.tmpl.html
<a id="test_link" href="somewhere.html">My test link</a>
js/test-link.js
js/test-link.js
$("a#test_link").click(changeTheTextOfTheLink)
function changeTheTextOfTheLink(e) {
e.preventDefault()
$("a#test_link").append(' is now longer');
}
specs/link-test.spec.js
规格/链接-test.spec.js
describe ("my basic jasmine jquery test", function(){
jasmine.getFixtures().fixturesPath = ''
var loadScript = function(path) {
appendSetFixtures('<script src="' + path + '"></script>');
};
beforeEach(function(){
loadFixtures('templates/link.tmpl.html');
loadScript('js/test-link.js');
});
it ("does some basic jQuery thing", function () {
$('a#test_link').click();
expect($("a#test_link")).toHaveText('My test link is now longer');
});
it ("does the same basic jQuery thing with a different event initiation method", function () {
$('a#test_link').trigger('click');
expect($("a#test_link")).toHaveText('My test link is now longer');
});
});
Spec Runner
规格赛跑者
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Spec Runner</title>
<link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.3/jasmine.css">
<script type="text/javascript" src="lib/jasmine-2.0.3/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-2.0.3/jasmine-html.js"></script>
<script src="lib/jasmine-2.2/boot.js"></script>
<script type="text/javascript" src="lib/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="lib/jasmine-jquery.js"></script>
<script type="text/javascript" src="specs/link-test.spec.js"></script>
</head>
<body>
</body>
</html>
回答by Guy Royse
Personally, I consider this to be a bug jasmine-jquery. I "solved" this by making my fixtures part of the SpecRunner.html. Not ideal but it works in simple cases.
就个人而言,我认为这是一个错误 jasmine-jquery。我通过使我的装置成为 SpecRunner.html 的一部分来“解决”这个问题。不理想,但它适用于简单的情况。