Hashrocket.com / blog

Large date time

Datetime select

posted on and written by Pavel Pravosud in

Image 100x100 pavel pravosud

Sometimes, default Date and DateTime Rails selects might be hard to use from your Cucumber tests. Luckily, we can always build some custom steps to work around this problem.

Consider a trivial user registration form with a birthday field:

= form_for User.new do |form|
  = form.label :birthday
  = form.date_select :birthday

It typically generates HTML similar to this:

<form accept-charset="UTF-8" action="/users" method="post">
  <label for="user_birthdate">Birthdate</label>
  <select id="user_birthdate_3i" name="user[birthday(3i)]"><option>Day</option>
  <select id="user_birthdate_2i" name="user[birthday(2i)]"><option>Month</option>
  <select id="user_birthdate_1i" name="user[birthday(1i)]"><option>Year</option>

There are two problems with this code:

  • The label does not actually point to any of the selects. Select ids are different from labels for attribute.
  • There are 3 separate selects for a single database field that could go in any arbitrary order.

Both problems make these types of fields super inconvenient to access from Capybara/Cucumber tests. Your usual select "1986/08/25", from: "Birthday" is not going to work here.

Custom Cucumber step to the rescue:

When /^I fill in "(.*?)" date field with "(.*?)"$/ do |field_name, date_components|
  label = find("label", text: field_name)
  select_base_id = label[:for]
  date_components.split(",").each_with_index do |value, index|
    select value.strip, from: "#{select_base_id}_#{index+1}i"

Now you can fill in date selects like this:

When I fill in "Birthdate" date field with "1986, Aug, 25"

This step could also easily be adopted to work with DateTime select fields. Notice that you have to pass date and time components in the order Rails expects it: year goes first, followed by month and then day.

Posted in Rails Quick Tips and tagged with rails, date, datetime, cucumber, select