Finally got autocomplete tests working at least with the Selenium driver.
The solution is to put focus on the field and issue a keydown event.
I confirmed this first with manual testing in a browser. If I use the mouse (not Ctrl-V) to paste a search term into an autocomplete field, nothing happens--no drop-down pick list is displayed. This is apparently the equivalent of what happens when Capybara sends a fill_in command. However, after the term is in the field, while focus is still on the field, if I touch any key, e.g. the Shift key, the pick list appears. So apparently the pick list only appears when a key is pressed.
Option 1
One solution is to extend the function from the original question as follows:
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
and then call it like this:
fill_autocomplete "to_contact_name", with: "Jone", select: "Bob Jones"
Option 2
A similar approach, adapted from the Steak test in the main rails3-jquery-autocomplete gem, uses the standard fill_in, followed by this 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
which is called like this:
fill_in "to_contact_name", :with => "Jone"
choose_autocomplete_result "Bob Jones", "#to_contact_name"
I've adopted the second approach for my tests. It seems pretty reliable with Selenium but doesn't work with webkit, which is too bad, since the Selenium tests are quite slow by comparison. A solution that works under webkit would be welcome!
Edit: For (non-R) code that works for all non-polar areas on earth, see here or here.
Unless you are dealing with data from a couple of exceptional areas (Svalbard and parts of Norway), this is a simple enough calculation that you might as well just do it yourself in R. Here is Wikipedia's description of how longitude relates to UTM Zone number:
The UTM system divides the surface of Earth between 80°S and 84°N latitude into 60 zones, each 6° of longitude in width. Zone 1 covers longitude 180° to 174° W; zone numbering increases eastward to zone 60 that covers longitude 174 to 180 East.
So, assuming that in your data longitudes to the west of the Prime Meridian are encoded as running from -180 to 0 degrees, here's an R-code version of the above:
long2UTM <- function(long) {
(floor((long + 180)/6) %% 60) + 1
}
# Trying it out for San Francisco, clearly in UTM Zone 10
# in the figure in the Wikipedia article linked above
SFlong <- -122.4192
long2UTM(SFlong)
# [1] 10
That expression could obviously be simplified a bit, but I think in this form the logic underlying its construction is most clear. The %% 60
bit is in there just in case some of your longitudes are greater than 180 or less than -180.
Best Answer
Actually, it seems that you can just send a \n to capybara's native set method and achieve the same effect (in a more flexible, driver agnostic way).
So in my code, this is currently working to trigger a form submit event (handled by JS):
(Note that, as the author of the pull request explains here, this only works if you're binding to the specific keydown event, not if you're binding to the form submit that should result from it.)