茉莉花 – 触发事件不起作用

我正在尝试测试的代码:

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

茉莉花规格:

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

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

 > "in spec" 

FWIW:

  • 我尝试过使用affixloadFixtures
  • 我尝试过使用$(".toggle_item").on("change"...$(".toggle_item").change...

gem清单:

 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 **

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

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

这是一个例子:

 // 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(){ // ie 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', ...); }) 

您链接的答案中的解释并不完全正确。 $('.selector').click(...)只是$('.selector').click(...)的别名或简写$('.selector').on('click', ...)所以更改为不会产生任何差异 – 它们在function上完全相同。

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

这是运行这个之间的区别:

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

结果:

 > 1 before > 2 middle > 3 after 

运行这个:

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

结果:

 > 1 before > 3 after > 2 middle 

另一个可能对您有所帮助的工具是委托事件监听器 。

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

例如:

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

这样做的好处是可以在.toggle_item存在之前.toggle_item添加事件侦听器,但是一旦添加了元素,就会触发侦听器。

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


原始答案

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

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

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

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

 > "Adding listener" > "in spec" 

而不是我们想要的:

 > "in spec" > "Adding listener"