自动完成方法拒绝在RSpec测试中触发

时间:2013-12-29 03:45:04

标签: ruby-on-rails-3 rspec capybara poltergeist

我在第4天尝试在RSpec测试中启动autocomplete场。在浏览器中超级工作,它非常难以在我的请求规范中运行。


更新:看起来我的RSpec / Capy脚本正在针对dev db而不是test db运行。我正在使用Pow,因此我不知道将default_url_options[:host]Capybara.app_hostCapybara.server_port设置为什么。我有一种感觉,如果我解决这个问题,它可能会有效。


堆栈是:

  • Rails 3.2.16
  • 水豚
  • RSpec的
  • 鬼驱/ PhantomJS
  • 的Pow
  • 宙斯
  • 工厂女孩

点击链接,点击按钮,fill_in字段一切都很棒。但是,当需要让这个自动完成工作时,它绝对拒绝工作。

我正在使用这种方法:

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]}")}
  Capybara::Screenshot.screenshot_and_open_image
  page.should have_selector('ul.ui-autocomplete li.ui-menu-item a')
  page.execute_script %Q{ $("#{selector}").trigger('mouseenter').click() }
end

我找到了herescreenshot行是我自己的。但是上面的一行:

  page.should have_selector('ul.ui-autocomplete li.ui-menu-item a')

返回false。它就像浏览器中的魅力一样。我不能为我的生活弄清楚为什么它不起作用。我已经尝试过我所知道的一切。我该怎么调试呢?

屏幕截图只显示了我期待的页面,并且字段填写正确。我甚至用“hello”警告对此进行了测试,我将其插入到autocomplete调用中。在浏览器中完美运行,但在测试中根本没有结果。

简而言之,看起来以下两行没有效果:

  page.execute_script %Q{ $("##{field}").trigger('focus') }
  page.execute_script %Q{ $("##{field}").trigger('keydown') }

3 个答案:

答案 0 :(得分:2)

我遇到了类似的问题,即使Capybara的文档说have_selector将等待AJAX​​调用完成,但它对我来说无效。

以下情况适用于我的情况:

def fill_in_autocomplete(field_label, field_class, options = {})
  field_id = "##{page.evaluate_script("$('#{field_class}').attr('id')")}"

  selector = "ul.ui-autocomplete li.ui-menu-item a"

  fill_in(field_label, with: options[:with])
  page.execute_script("$('#{field_id}').trigger('focus')")
  page.execute_script("$('#{field_id}').trigger('keydown')")

  sleep(2) # Hack! not sure why the line below isn't working...
  #expect(page).to have_selector(selector, text: options[:with])

  page.execute_script("$('#{selector}').click()")
end

您可以像这样调用上面的方法:

fill_in_autocomplete('Some label', '.js-some-field', with: 'Some value'

我不想传递字段ID而是选择了一个类,这就是帮助器中的第一行根据元素的类获取ID的原因。

答案 1 :(得分:0)

这种异步调用对于排除故障非常棘手。正如Xaid建议的那样,有时只需要进行任意的睡眠即可完成工作。

我在自己的编码中发现,通常发生的事情是,尽管Capybara试图智能地等待AJAX​​发挥其魔力,但是有些事情导致Capybara相信条件得到满足它会在你没有的时候继续实际上已经准备好了。

深入研究Capybara的代码,您会发现异步行为的延迟是通过同步包装函数完成的,该函数是Node :: Base类的一部分。 (见这里,如果你很好奇它是如何运作的:https://github.com/jnicklas/capybara/blob/master/lib/capybara/node/base.rb#L73

基本上,它正在为您执行一系列等待命令(每次0.05秒)并捕获任何“我找不到该元素”异常,直到超时(默认为2秒)过去。如果出于任何原因,您正在等待的元素在您预期之前存在,它将停止等待并继续前进。

在无头浏览器中存储页面的HTML可能是一个很好的故障排除技巧。尝试在截屏代码之前在代码中插入puts page.body。那应该输出页面的HTML。代码是否包含您期望的ul.ui-autocomplete li.ui-menu-item a?在夏德建议的延迟之后怎么样?它存在吗?

对于非常棘手的问题,我会将pry gem添加到我的项目中并将binding.pry插入代码中。这让我可以在测试中使用浏览器来查看它所看到的内容。当然,由于时间问题,我通常不能足够快地看到它看到的东西,但即使这是一个线索。

希望这些故障排除技巧很有用。

答案 2 :(得分:0)

我有这个问题,没有提出的解决方案可以解决它。尝试查找ul.ui-autocomplete元素时,我的测试总是失败。我终于注意到,jQuery自动完成将ul附加到html页面的末尾而不是有问题的输入字段。在我的规范中,我遵循within my_form do明确定位表单的做法,并执行此块中的所有fill_in内容:

within my_form do
  fill_autocomplete …
end

当然,这个表单元素永远找不到ul附加的OUTSIDE。我的解决方案很简单:在初始化自动完成时使用jQuery自动完成的属性appendTo: '#id_of_input_field'。现在它可以找到我的ul,一切正常。