Javascript 轨道&x2B;jasmineajax:测试由Ajax:success触发的代码的正确方法是什么(jqueryujs)

Javascript 轨道&x2B;jasmineajax:测试由Ajax:success触发的代码的正确方法是什么(jqueryujs),javascript,jquery,ruby-on-rails,ajax,jasmine,Javascript,Jquery,Ruby On Rails,Ajax,Jasmine,我试图测试一个内部库,它在ajax:success事件中触发了一些JS行为 库创建的链接如下所示: <%= link_to 'click here', '/some_path', class: 'special-link', remote: true %> $document.on('myCustomEvent', '.some_selector', somecode.custom_func); $document.on('ajax:error', '.some_selector'

我试图测试一个内部库,它在
ajax:success
事件中触发了一些JS行为

库创建的链接如下所示:

<%= link_to 'click here', '/some_path', class: 'special-link', remote: true %>
$document.on('myCustomEvent', '.some_selector', somecode.custom_func);
$document.on('ajax:error', '.some_selector', somecode.failure_func);
该库在浏览器中按预期工作。但是,当我试图在Jasmine中通过调用
$('.special link').click()
来测试库时,无法观察到对DOM的理想效果

问题似乎是,
ajax:success
事件没有被触发:

describe 'my library', ->
  beforeEach ->
    MagicLamp.load('fixture') # Fixture library that injects the link above to the DOM
    jasmine.Ajax.install()
    jasmine.Ajax.stubRequest('/some_path').andReturn({
      responseText: 'response that is supposed to trigger some effect on the DOM'})

  afterEach ->
    jasmine.Ajax.uninstall()

  # Works. The fixtures are loading properly
  it '[sanity] loads fixtures correctly', ->
    expect($('.special-link').length).toEqual(1)

  # Works. The jquery-ujs correctly triggers an ajax request on click
  it '[sanity] triggers the ajax call', ->
    $('.special-link').click() 
    expect(jasmine.Ajax.requests.mostRecent().url).toContain('/some_path')

  # Works. Code that tests a click event-triggering seems to be supported by Jasmine
  it '[sanity] knows how to handle click events', ->
    spy = jasmine.createSpy('my spy')
    $('.special-link').on 'click', spy
    $('.special-link').click()
    expect(spy).toHaveBeenCalled()

  # Does not work. Same code from above on the desired `ajax:success` event does not work
  it 'knows how to handle ajax:success events', ->
    spy = jasmine.createSpy('my spy')
    $('.special-link').on 'ajax:success', spy
    $('.special-link').click()
    expect(spy).toHaveBeenCalled()

测试在
ajax:success
事件中运行的代码对DOM的影响的正确方法是什么?

您是否尝试过简单地监视
ajax
函数?为此,需要使用
spyOn
并强制它调用
success
事件处理程序。这将让您测试在调用时预期会发生什么

it 'knows how to handle ajax:success events', ->
  spyOn($, "ajax").and.callFake( (e) ->
    e.success({});
  )

  $('.special-link').click()

  # expect some method to be called or something to be changed in the DOM

下面是我们如何在我的团队中处理这类事情

it 'knows how to handle ajax:success events', ->
  spyOn($.fn, 'on');
  $('.special-link').click()
  expect($.fn.on).toHaveBeenCalledWith('ajax:success', 
                                       '.special-link'
                                       some_func);
此模式也可以很好地扩展到测试其他“on”事件。假设我们有一些jQuery,如下所示:

<%= link_to 'click here', '/some_path', class: 'special-link', remote: true %>
$document.on('myCustomEvent', '.some_selector', somecode.custom_func);
$document.on('ajax:error', '.some_selector', somecode.failure_func);
然后我们可以使用以下模式对其进行测试:

beforeEach ->
  spyOn($.fn, 'on');
  somecode.init();
测试Ajax故障

it('indicates failure after ajax error', ->
  expect($.fn.on).toHaveBeenCalledWith('ajax:error',
                                       '.some_selector',
                                       somecode.failure_func);
测试Ajax是从自定义事件调用的

it('indicates ajax call from custom event', ->
  expect($.fn.on).toHaveBeenCalledWith('myCustomEvent',
                                       '.some_selector',
                                       somecode.custom_func);

经过大量调试,我找到了一个解决方案

当我发布我的问题时,我犯了3个严重错误

错误#1:
jasmine.Ajax.stubRequest
路径不是相对的 Ajax调用没有正确地存根,因为路径不应该是相对的
/some\u路径
,而应该是绝对的
http://localhost:3000/some_path
从浏览器进行测试时

换句话说,不是:

jasmine.Ajax.stubRequest('/some_path')
jasmine.Ajax.stubRequest(/.*\/some_path/).andReturn({
  responseText: 'response that is supposed to trigger some effect on the DOM'})
我应该使用regexp版本:

jasmine.Ajax.stubRequest(/.*\/some_path/)
错误2:
jasmine.Ajax.andReturn
必须包含coentType 而不是:

jasmine.Ajax.stubRequest('/some_path')
jasmine.Ajax.stubRequest(/.*\/some_path/).andReturn({
  responseText: 'response that is supposed to trigger some effect on the DOM'})
我应该这样做:

jasmine.Ajax.stubRequest(/.*\/some_path/).andReturn({
      contentType: 'text/html;charset=UTF-8',
      responseText: 'response that is supposed to trigger some effect on the DOM'})
如果没有它,将触发
ajax:error
,而不是
ajax:success
,并触发
parseerror

错误3:
ajax:success
处理程序被异步调用 这些代码行:

spy = jasmine.createSpy('my spy')
$('.special-link').on 'ajax:success', spy
$('.special-link').click()
expect(spy).toHaveBeenCalled()
不要工作,因为调用
spy()
ajax:success
处理程序在到达
expect(spy).toHaveBeenCalled()
后被异步调用。您可以在中阅读更多关于此的信息

把它们放在一起 这是有效的代码,只关注最后的
it
语句,这是原始问题背后的主要意图:

describe 'my library', ->
  beforeEach ->
    MagicLamp.load('fixture') # Fixture library that injects the link above to the DOM
    jasmine.Ajax.install()
    jasmine.Ajax.stubRequest(/.*\/some_path/).andReturn({
      contentType: 'text/html;charset=UTF-8',
      responseText: 'response that is supposed to trigger some effect on the DOM'})

  afterEach ->
    jasmine.Ajax.uninstall()

  # Restructuring the original `it` statement to allow async handling
  describe 'ajax:success event handling', ->
    spy = jasmine.createSpy('spy')

    # Ensures no `it` statement runs before `done()` is called
    beforeEach (done) ->
      $('.special-link').on 'ajax:success', ->
        spy()
        done()

      $('.special-link').click()    

    it 'knows how to handle ajax:success events', ->
      expect(spy).toHaveBeenCalled()

希望这对其他人有帮助。

我最近回答了类似的问题,这有什么帮助吗?