【问题标题】:rails3-jquery-autocomplete: how to test with RSpec and Capybara?rails3-jquery-autocomplete:如何使用 RSpec 和 Capybara 进行测试?
【发布时间】:2012-11-02 00:53:17
【问题描述】:

我正在使用 Rails 3.2.8 和

  • gem 'jquery-rails', '2.1.2'
  • gem 'rails3-jquery-autocomplete', '1.0.9'
  • gem 'rspec-rails', '2.11.4'
  • gem '水豚','1.1.3'
  • gem 'capybara-webkit', '0.12.1'

我最近将选择下拉菜单转换为自动完成(使用 rails3-jquery-autocomplete),并正在尝试更新我的请求规范以填写自动完成。

我的方法是创建一个 helper,如 this gist 所示:

def fill_autocomplete(field, options = {})
  fill_in field, :with => options[:with]

  selector = "ul.ui-autocomplete a:contains('#{options[:select]}')"

  page.should have_selector selector
  page.execute_script "$(\"#{selector}\").mouseenter().click()"
end

如果我使用 Webkit 进行测试,测试会失败并显示以下消息:

expected css "ul.ui-autocomplete a:contains('Firstname Lastname')" to return something.

如果我使用 Selenium 进行测试,当我在 Firefox 中进行测试时,我确实没有看到下拉选择列表出现。添加sleep 3 以等待下拉菜单没有帮助。

我看到here 有一个与 capybara-webkit 相关但有些旧的问题,当一个字段被填写时,它会立即变得模糊,这当然会阻止自动完成选择列表出现。但这似乎与其他已使其工作的人不相符。

目前是否可以使用 RSpec 和 Capybara 测试包含 rails3-jquery-autocomplete 字段的表单?如何?如果没有,有没有办法手动填写相应的隐藏 id 字段,以便我仍然可以测试表单是否创建了正确的数据?

【问题讨论】:

    标签: jquery ruby-on-rails jquery-ui rspec capybara


    【解决方案1】:

    至少在 Selenium 驱动程序中终于得到了自动完成测试。

    解决方案是将焦点放在字段上并发出 keydown 事件。

    我首先通过在浏览器中的手动测试确认了这一点。如果我使用鼠标(不是 Ctrl-V)将搜索词粘贴到自动完成字段中,则不会发生任何事情——不显示下拉选择列表。这显然等同于 Capybara 发送 fill_in 命令时发生的情况。但是,在术语在字段中之后,当焦点仍然在字段上时,如果我触摸任何键,例如Shift 键,出现选择列表。所以显然选择列表仅在按下键时出现。

    选项 1

    一种解决方案是从原始问题扩展功能如下:

    def fill_autocomplete(field, options = {})
      fill_in field, :with => options[:with]
    
      page.execute_script %Q{ $('##{field}').trigger("focus") }
      page.execute_script %Q{ $('##{field}').trigger("keydown") }
      selector = "ul.ui-autocomplete a:contains('#{options[:select]}')"
    
      page.should have_selector selector
      page.execute_script "$(\"#{selector}\").mouseenter().click()"
    end
    

    然后这样称呼它:

    fill_autocomplete "to_contact_name", with: "Jone", select: "Bob Jones"
    

    选项 2

    类似的方法,改编自主要 rails3-jquery-autocomplete gem 中的 Steak test,使用标准的 fill_in,然后是这个 choose_autocomplete_result:

    def choose_autocomplete_result(item_text, input_selector="input[data-autocomplete]")
      page.execute_script %Q{ $('#{input_selector}').trigger("focus") }
      page.execute_script %Q{ $('#{input_selector}').trigger("keydown") }
      # Set up a selector, wait for it to appear on the page, then use it.
      item_selector = "ul.ui-autocomplete li.ui-menu-item a:contains('#{item_text}')"
      page.should have_selector item_selector
      page.execute_script %Q{ $("#{item_selector}").trigger("mouseenter").trigger("click"); }
    end
    

    这样称呼:

    fill_in "to_contact_name", :with => "Jone"
    choose_autocomplete_result "Bob Jones", "#to_contact_name"
    

    我在测试中采用了第二种方法。 Selenium 似乎很可靠,但不适用于 webkit,这太糟糕了,因为相比之下 Selenium 测试相当慢。欢迎在 webkit 下工作的解决方案!

    【讨论】:

    • 是的,它不适用于 Webkit。我在 capybara + poltergeist(webkit env) 上对其进行了测试,它在 have_selector 验证时崩溃了。当我通过截屏进行调试时,我发现确实生成了自动完成项,但页面对象无法识别它
    • 您的选项 1 解决方案不起作用,因为 :contains 不是有效的 W3C CSS 选择器(这仅是 jQuery)。我用我名下的stackoverflow.com/questions/6355586/… 中列出的解决方案修复了它
    【解决方案2】:

    我自己也遇到了同样的痛点。在花了几个小时之后,我有了一个可以同时使用 selenium 和 polstergeist 的好帮手,而且没有使用 sleep()。以下代码已经用 Capybara 2.1.0 测试过:

      def fill_autocomplete(field, options = {})
        fill_in field, with: options[:with]
    
        page.execute_script %Q{ $('##{field}').trigger('focus') }
        page.execute_script %Q{ $('##{field}').trigger('keydown') }
        selector = %Q{ul.ui-autocomplete li.ui-menu-item a:contains("#{options[:select]}")}
    
        page.should have_selector('ul.ui-autocomplete li.ui-menu-item a')
        page.execute_script %Q{ $('#{selector}').trigger('mouseenter').click() }
      end
    

    基本上,我告诉Capybara填写输入字段然后使用JS触发keydown事件以激活自动完成。但是,我利用 page.should have_selector('ul.ui-autocomplete li.ui-menu-item a') 等到下拉列表出现,而不是 sleep()。然后我用JS触发mouseenter事件然后点击。我希望有比使用 JS eval 做事更好的方法,但这是我能想到的最可靠的解决方案。

    【讨论】:

    • Keydown 没有使用 Poltergeist 触发自动完成代码。我通过在屏幕上添加一个虚拟输入框并为其附加一个 keydown 侦听器来验证这一点,它只会使测试对象可见或不可见。然后我在测试前后截图。所以我知道 keydown 事件正在触发,但无论出于何种原因,它都没有触发在浏览器中运行良好的自动完成代码。你有什么想法吗?我已经为此花费了将近 48 个小时的工作时间,但我无法克服它。
    【解决方案3】:

    如果有人需要一些代码来激发灵感(即使在阅读了这个帖子之后我也花了一些时间),这很有效:

          context "with 5 items results" do
            before do
              5.times { FactoryGirl.create(:item, title: "chinese " + random_string(5) ) }
              page.execute_script("$('input#search_param').val('chinese')")
              page.execute_script("$('input#search_param').trigger('focus')")
              page.execute_script("$('input#search_param').trigger('keydown')")
            end
            specify { page.evaluate_script("$('input#search_param').val()").should == 'chinese' }
            specify { page.should have_css "#autocomplete-menu li", count: 5 }
          end
    

    感谢 Mark Berry 的启发。

    【讨论】:

      【解决方案4】:

      另一种选择是 capybara send_keys 方法:

      find('#my_object_id').send_keys 'bob'

      我更喜欢这个选项而不是注入 javascript 来触发 keydown/focus/mouseenter 事件。

      【讨论】:

        【解决方案5】:

        我没有使用 page.execute_script,而是在输入后用空白填充输入,以便触发事件。

        fill_in("query", :with => "ma")
        fill_in("query", :with => "")
        # autocomplete suggestions will come up
        all('.autocomplete div').first.should have_content("mango")
        # other assertions
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-08-26
          • 2011-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多