UPDATE: I have fixed this problem after lots of painstaking work on my own. I am happy to be a resource to anybody needing a hand with this. Here is a gist of my working setup.
I have tried every solution I could find Google and SO. Here are some different things I have tried:
page.execute_script %Q{$('#{selector}').val('#{value}').trigger('keydown')}
and
fill_in field, with: options[:with]
page.execute_script %Q{ $('##{field}').trigger('focus') }
page.execute_script %Q{ $('##{field}').trigger('keydown') }
This is what fails:
page.should have_selector('ul.ui-autocomplete li.ui-menu-item a')
But it's definitely there when I look at it in Firebug and test it in the browser.
Here are all of the details, including a restatement of those above. Remember, the autocomplete field works fine in the browser.
listing_integration_spec.rb
require "spec_helper"
describe "Listing Integration" do
let!(:user) { login_user }
it "lets a user add information listing", js: true do
listing = create(:listing, user: user)
click_link('Additional Information')
click_link('Create')
fill_autocomplete('listings_search', with: listing.item_id)
end
end
spec/support/feature_helper.rb
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[:with]}')}
page.should have_selector('ul.ui-autocomplete li.ui-menu-item a')
page.execute_script %Q{ $("##{selector}").trigger('mouseenter').click() }
end
ERB from view template
<%= simple_fields_for :listings do |f| %>
<%= f.input :search, label: "Search by Listing", required: true %>
<% end %>
and the Coffeescript:
$("#listings_search").autocomplete
source: (request, response) ->
options =
term: request.term
$.get "/search_listings", options, (data) ->
if data.length == 0
alert "No listings found."
response data
minLength: 2
select: (event, ui) ->
add_listing_hash =
type: "GET"
url: "/add_listing"
data: { id: ui.item.id }
success: () ->
$.ajax(add_listing_hash)
I was able to test my autocompleting text field with Poltergeist without much trouble. The main thing to know about is Poltergeist's
.native.send_keys
method.Hacking together a summary out of the Cucumber steps where these lines of code actually live in my project:
Then I submit the form and assert the expected results on the following page in the usual way.
wait_until
(a reimplementation of a method which was removed from Capybara 2) takes a block which returns true when we should stop waiting. It's faster than waiting for 5 seconds or whatever every time.JS drivers are generally meh, they're slow and not single one of them covers 100% of function, and they're often quirky and hard to debug, but I'm sure you've got that figured out by now.
I've got similar piece of code working on rails 3.2, minitest and poltergeist 1.3.0 (an ajaxed dropdown) but it kind of breaks periodically for no good reason (one might say it has a poltergeist? I have already resorted switching that test between selenium and poltergeist a couple times so far), not sure why autocompleter wouldn't work for you but it feels like a bug,
submit issue to https://github.com/jonleighton/poltergeist (you already have? https://github.com/jonleighton/poltergeist/issues/439), try changing to selenium or webkit, see if it works, you can use a different driver in this one test if it gets you out of the woods (it beats losing days of work over a widget that works).
I've found several solutions online, none of which work with current versions of Poltergeist, Capybara, and Autocomplete. But I learned enough from them to make a working helper method, with no sleep calls.
Example usage:
I have a
page
argument because I'm using SitePrism - if you're not, you can strip it out.I'm using this with:
I had this problem and no proposed solution could solve it. My tests always failed when trying to find the
ul.ui-autocomplete
element. I finally noticed, that jQuery autocomplete appends theul
to the end of the html page and NOT to the input field in question. In my spec, I follow the practice of targeting my forms explicitly bywithin my_form do
and doing all thefill_in
stuff inside this block:Of course this could never find the
ul
attached OUTSIDE this form element. My solution was simple: Use jQuery autocomplete's attributeappendTo: '#id_of_input_field'
when initializing autocomplete. Now it can find myul
and everything works fine.I think perhaps you need a mixture of triggering KEYDOWN, but also setting the keycode to DOWN.
e.g.
Here is a working jsfiddle example showing an item selected by the autocomplete: http://jsfiddle.net/alexkey/74BST/ I'm not sure why you need to trigger keydown twice, but that's a problem to solve separately (if a problem at all).
However I'm not familiar with the unit testing framework you are using, but I hope the above helps.
Credit goes to JQuery AutoComplete, manually select first searched item and bind click
I'm using the example code form: http://api.jqueryui.com/autocomplete/#entry-examples
The autocomplete unit tests that the jquery-ui team uses may come in useful for inspiration: https://github.com/jquery/jquery-ui/tree/master/tests/unit/autocomplete
Also a reference to the keycode: http://api.jqueryui.com/jQuery.ui.keyCode/