rails3-jquery-autocomplete:如何使用RSpec和Capybara进行测试?

时间:2012-11-02 00:53:18

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

我正在使用Rails 3.2.8和

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

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

我的方法是创建一个帮助器,如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字段,以便我仍然可以测试表单是否创建了正确的数据?

5 个答案:

答案 0 :(得分:10)

最后,自动完成测试至少使用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下运行的解决方案!

答案 1 :(得分:4)

我自己也遇到了同样的痛点。在花了几个小时后,我有一个好帮手,既可以使用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事件来激活自动完成。但是,我利用等待下拉列表出现的sleep()而不是page.should have_selector('ul.ui-autocomplete li.ui-menu-item a')。然后我用JS来触发mouseenter事件然后点击。我希望有更好的方法,而不是使用JS eval,但这是我可以提出的最可靠的解决方案。

答案 2 :(得分:2)

如果有人需要一些代码来获取灵感(即使在阅读完这篇帖子后我也花了一些时间),这样可行:

      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的灵感。

答案 3 :(得分:1)

另一种选择是水豚send_keys方法:

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

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

答案 4 :(得分:0)

我没有使用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