【问题标题】:Rails + Jasmine-Ajax: what is the correct way to test code triggered by `ajax:success` (jquery-ujs)Rails + Jasmine-Ajax:测试由`ajax:success`触发的代码的正确方法是什么(jquery-ujs)
【发布时间】:2016-08-02 23:33:48
【问题描述】:

我正在尝试测试某个内部库,该库在ajax:success 事件上触发了一些 JS 行为。

该库创建一个如下所示的链接:

<%= link_to 'click here', '/some_path', class: 'special-link', remote: true %>

在库的JS部分有事件绑定代码,这是我想通过它对DOM的影响进行黑盒测试的部分

$(document).on 'ajax:success', '.special-link', (e, data, status, xhr) ->
  # Code that has some effect on the DOM as a function of the server response

该库在浏览器中按预期工作。但是,当我尝试通过调用 $('.special-link').click() 来测试 Jasmine 中的库时,无法观察到对 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的影响的正确方法是什么?

【问题讨论】:

标签: javascript jquery ruby-on-rails ajax jasmine


【解决方案1】:

您是否尝试过简单地监视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

【讨论】:

    【解决方案2】:

    以下是我们在我的团队中处理此类事情的方式。

    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:

    $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】:

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

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

      错误 #1:jasmine.Ajax.stubRequest 路径不是相对的

      Ajax 调用未正确存根,因为从浏览器测试时路径不应是相对的 /some_path,而是绝对的 http://localhost:3000/some_path

      换句话说,而不是:

      jasmine.Ajax.stubRequest('/some_path')
      

      我应该使用正则表达式版本:

      jasmine.Ajax.stubRequest(/.*\/some_path/)
      

      错误 #2:jasmine.Ajax.andReturn 必须包含 cotentType

      代替:

      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:successparseerror

      错误 #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() 后被异步调用。您可以在Jasmine documentation 中阅读更多相关信息。

      把它们放在一起

      这是有效的代码,只关注最后一个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()
      

      希望这对其他人有所帮助。

      【讨论】:

        猜你喜欢
        • 2011-06-30
        • 2022-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多