2012-11-02 106 views
7

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

  • 宝石 'jQuery的轨道', '2.1.2'
  • 宝石 'Rails3中,jQuery的自动完成', '1.0.9'
  • 宝石'RSpec的护栏', '2.11.4'
  • 宝石 '水豚', '1.1.3'
  • 宝石 '水豚 - WebKit的', '0.12.1'

我最近转换一个选择下拉到自动完成(我们ing 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,这样我仍然可以测试该表单是否创建了正确的数据?

回答

9

终于有了自动完成测试,至少在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的自动完成宝石从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

是的,它没有与Webkit的工作。我在capybara + poltergeist(webkit env)上测试它,它在has_selector验证中崩溃。当我通过截屏视频进行调试时,发现自动完成项目已生成,但页面对象无法识别它 – raykin

+2

由于':contains'无效W3C CSS选择器(这是仅jQuery)。我使用http:// stackoverflow中列出的解决方案修复了它。com/questions/6355586/testing-jquery-autocomplete-ui-with-cucumber根据我的名字 –

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 
3

我自己也碰到了同样的痛点。花了几个小时后,我有一个好的助手,可以同时使用硒和polstergeist,并且不会使用sleep()。下面的代码已经过测试,水豚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 

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

+1

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

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 

感谢马克·贝瑞为灵感。

1

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

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

我喜欢这个选项,在注入的JavaScript火的keydown /对焦/的mouseenter事件。

相关问题