茉莉花 - 触发事件不起作用 [英] Jasmine - trigger event not working

查看:182
本文介绍了茉莉花 - 触发事件不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试测试的代码:

  $(。toggle_item)。on(更改, function(){
console.log(change triggered)
item_name = $(this).data(name);
value = $(this).prop(checked );
if(Item.isValid(item_name)&& cartModule.isUnique(item_name)){
cartModule.toggleItem(item_name,value);
}
} )

茉莉花规格:

  describe(更改切换项,function(){
beforeEach(function(){
console.log(in spec)
affix(。 toggle_item [data-name ='ladder'])
spyOn(cartModule,isUnique)
spyOn(Item,isValid)
$(。toggle_item)。trigger( 更改)
})

it(应检查项目的有效性和购物车的唯一性,function(){
expect(Item.isValid).toHaveBeenCalledWith( 阶梯)
expect(cartModule.isUnique).toHaveBeenCalledWith(阶梯)
})
})

控制台日志输出表明触发器未触发。日志输出:

 > 在规格中

FWIW:




  • 我尝试过使用 affix loadFixtures

  • 我尝试过使用 $(。toggle_item)。on(更改... $(。toggle_item) .change ...



宝石清单:

  jasmine(2.7.0)
jasmine-core(2.8.0,2.7.0)
jasmine-jquery-rails(2.0.3)
jasmine-rails(0.14.1)


解决方案

* *更新的答案:2018-02-03 **



这里的根本问题是你的代码正在运行太早,在你的灯具有之前已经设置。这与在所有测试之前加载代码不同。在加载之后,您需要能够控制代码运行的时间。



这更多地与您编写代码的方式有关,以便可以对其进行测试,并且在很大程度上与t无关他实际上用于测试的工具和库。



这是一个例子:

  //无法测试此表达式 - 它会在加载后立即运行
1 + 2


//这类似于上面的一行 - 它试图尽快添加事件监听器
//遇到代码行。如果你在这行之前没有设置灯具
//则你无法测试它。
$('。toggle_item')。on('change',...);


//这是一个可测试的代码示例
//它是可测试的,因为我们从代码中分离了代码
//的加载**调用代码**。
function add(){
//即此表达式仅在调用`add()`时运行。
返回1 + 2;
}


//这是一个示例,可以在添加事件侦听器时添加更多控制权。
$(function(){
//这个表达式在`$ .ready`被触发时运行(又名`DOMContentLoaded`)
//如果你可以延迟`$ .ready`直到你的设置灯具然后这将工作。
$('。toggle_item')。on('change',...);
})






你的链接答案并不完全正确。 $('。selector')。click(...)只是 $('。selector')的别名或简写。 on('click',...)所以更改为没有任何区别 - 它们在功能上完全相同。



在这种情况下,答案实际上有效的原因是因为事件监听器被添加到 $。ready()事件中,而不是在加载代码后立即添加。 / p>

这是运行它之间的区别:

  console.log(' 1之前'); 
console.log('2 middle');
console.log('3 after');

结果:

 > 1美元之前
> 2中$
>
之后

运行此:

  console.log('1 before'); 
$(function(){
console.log('2 middle');
});
console.log('3 after');

结果:

 > 1美元之前
>
后的3> 2中$






另一个可以帮到你的工具是委派的事件监听器



基本上,您可以向DOM树中的元素添加单个事件侦听器,该元素侦听来自特定子选择器的事件。



例如:

  $(function(){
$(document).on('change','。toggle_item',function( ){

});
})

福利这是事件监听器可以提前添加,事件在 .toggle_item 之前存在,但是一旦添加了元素,将触发监听器。



使用事件代理有一些注意事项(例如,当使用 event.preventDefault() event.stopPropagation时( ))但它们仍然是一个非常有用的工具。






Orig回答



在您测试的代码中,您是否能够在添加事件监听器时控制/延迟?



我怀疑你的代码试图在词缀(。toggle_item [data-name]之前将事件监听器添加到 .toggle_item ='ladder'])语句正在测试中运行。

  console.log( '添加监听器')
$(。toggle_item)。on(change,function(){
console.log(change triggered)
...
});

如果你得到的话,你会知道它是乱序的:

 > 添加监听器
> 在规格中

而不是我们想要的:

 > 在规格中
> 添加监听器


Code that I'm trying to test:

$(".toggle_item").on("change", function() {
  console.log("change triggered")
  item_name = $(this).data("name");
  value = $(this).prop("checked");
  if (Item.isValid(item_name) && cartModule.isUnique(item_name)) { 
    cartModule.toggleItem(item_name, value); 
  }
})

Jasmine spec:

describe("changing toggle item", function() {
  beforeEach(function() {
    console.log("in spec")
    affix(".toggle_item[data-name='ladder']")
    spyOn(cartModule, "isUnique") 
    spyOn(Item, "isValid")
    $(".toggle_item").trigger("change")
  })

  it("should check item for validity & cart for uniqueness", function() {
    expect(Item.isValid).toHaveBeenCalledWith("ladder")
    expect(cartModule.isUnique).toHaveBeenCalledWith("ladder")
  })
})

The console log output indicates that the trigger did not fire. Log output:

> "in spec"

FWIW:

  • I have tried using both affix and loadFixtures
  • I have tried using both $(".toggle_item").on("change"... and $(".toggle_item").change...

Gem list:

jasmine (2.7.0)
jasmine-core (2.8.0, 2.7.0)
jasmine-jquery-rails (2.0.3)
jasmine-rails (0.14.1)

解决方案

** Updated answer: 2018-02-03**

The fundamental issue here is that your code is running too early, before your fixtures have been set up. This is different to loading your code before all of your tests. You need to be able to control when your code runs after it has been loaded.

This is more to do with how you write your code so that it can be tested, and is largely independent of the tools and libraries that are actually being used for testing.

Here is an example:

// There is no way to test this expression - it runs as soon as it is loaded
1 + 2


// This is similar to the line above - it tries to add the event listener as soon
// as the line of code is encountered. If you haven't set up fixtures before this line is run
// then you can't test it.
$('.toggle_item').on('change', ...);


// Here is an example of code that is testable
// It is testable because we have separated out the loading of the code 
// from the **invocation** of the code.
function add(){
    // i.e. This expression will only run when `add()` is invoked.
    return 1 + 2;
}


// Here is an example that adds a bit more control over when the event listeners are added.
$(function(){
    // This expression runs when `$.ready` is fired (aka `DOMContentLoaded`)
    // If you can delay `$.ready` until your fixtures are set up then this will work.
    $('.toggle_item').on('change', ...);
})


The explanation in your linked answer isn't quite right. $('.selector').click(...) is just an alias or short-hand for $('.selector').on('click', ...) so changing to that won't make any difference - they are functionally exactly the same.

The reason that answer actually works in that case is because the event listener is being added in the $.ready() event instead of immediately as soon as the code is loaded.

It's the difference between running this:

console.log('1 before');
console.log('2 middle');
console.log('3 after');

Result:

> 1 before
> 2 middle
> 3 after

And running this:

console.log('1 before');
$(function(){
    console.log('2 middle');
});
console.log('3 after');

Result:

> 1 before
> 3 after
> 2 middle


Another tool that might help you here is delegated event listeners.

Bascially, you add a single event listener to an element further up the DOM tree which listens for events from particular child selectors.

e.g.:

$(function(){
    $(document).on('change', '.toggle_item', function(){

    });
})

The benefit of this is that the event listener can be added early, event before .toggle_item exists, but the listeners will be fired once the elements have been added.

There are some caveats to using event delegates (e.g. when using event.preventDefault() or event.stopPropagation()) but they are still a very useful tool.


Original answer

In your code under test are you able to control/delay when the event listener is added?

I suspect that your code is trying to add the event listener to .toggle_item before the affix(".toggle_item[data-name='ladder']") statement is being run in your tests.

console.log('Adding listener')
$(".toggle_item").on("change", function() {
    console.log("change triggered")
    ...
});

You'll know it's out of order if you get:

> "Adding listener"
> "in spec"

Instead of what we want:

> "in spec"
> "Adding listener"

这篇关于茉莉花 - 触发事件不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆