Skip to content

Commit 409152f

Browse files
committed
add support for alternative select boxes date field helpers
I'm adding another spec forcing select boxes view helper. The helper has been around since Rails 5. It's not a problem to run the test in older versions
1 parent 1e919ed commit 409152f

File tree

4 files changed

+80
-13
lines changed

4 files changed

+80
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ on how to contribute to Cucumber.
1313

1414
### Fixed
1515

16-
*
16+
* Date input support in Rails 7 ([#535](https://github.com/cucumber/cucumber-rails/pull/535) [mgrunberg])
1717

1818
## [v2.5.0](https://github.com/cucumber/cucumber-rails/compare/v2.4.0...v2.5.0) (2022-03-07)
1919

features/capybara_javascript_drivers.feature

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,53 @@ Feature: Capybara Javascript Drivers
4646
6 steps (6 passed)
4747
"""
4848

49+
Scenario: Support non HTML5 date inputs
50+
Given I have created a new Rails app and installed cucumber-rails
51+
And I force selenium to run Firefox in headless mode
52+
When I run `bundle exec rails g scaffold appointment name:string when:datetime`
53+
And I force "app/views/appointments/_form.html.erb" to use select boxes for dates
54+
And I write to "features/create_appointment.feature" with:
55+
"""
56+
@javascript
57+
Feature: Create appointments
58+
Scenario: Create an appointment using the Web Interface
59+
Given I am on the new appointment page
60+
When I fill in "Cucumber Trainee" for "Name"
61+
And I select "2026-02-20 15:10:00 UTC" as the "When" date and time
62+
And I press "Create Appointment"
63+
Then I should see "Cucumber Trainee"
64+
And I should see "2026-02-20 15:10:00 UTC"
65+
"""
66+
And I write to "features/create_appointment_steps.rb" with:
67+
"""
68+
Given('I am on the new appointment page') do
69+
visit new_appointment_path
70+
end
71+
72+
When('I fill in {string} for {string}') do |value, field|
73+
fill_in(field, with: value)
74+
end
75+
76+
When('I press {string}') do |button|
77+
click_button(button)
78+
end
79+
80+
When('I select {string} as the {string} date and time') do |datetime, selector|
81+
select_datetime(datetime, from: selector)
82+
end
83+
84+
Then('I should see {string}') do |text|
85+
expect(page).to have_content(text)
86+
end
87+
"""
88+
And I run `bundle exec rake db:migrate`
89+
And I run `bundle exec rake cucumber`
90+
Then the feature run should pass with:
91+
"""
92+
1 scenario (1 passed)
93+
6 steps (6 passed)
94+
"""
95+
4996
Scenario: Use direct DB injection
5097
Given I have created a new Rails app and installed cucumber-rails
5198
And I force selenium to run Firefox in headless mode

features/step_definitions/cucumber_rails_steps.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@
6767
step 'I append to "features/support/env.rb" with:', selenium_config
6868
end
6969

70+
Given('I force {string} to use select boxes for dates') do |file|
71+
content = File.read(expand_path(file))
72+
73+
overwrite_file(file, content.gsub(/\.(datetime|time|date)_field/, '.\1_select'))
74+
end
75+
7076
When('I run the cukes') do
7177
run_command_and_stop('bundle exec cucumber')
7278
end

lib/cucumber/rails/capybara/select_dates_and_times.rb

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ module SelectDatesAndTimes
88
# Select a Rails date. Options hash must include from: +label+
99
def select_date(date, options)
1010
date = Date.parse(date)
11-
if ::Rails::VERSION::MAJOR >= 7
12-
# Rails 7 generates date fields using input type="date". Capybara support's them
11+
base_dom_id = get_base_dom_from_options(options)
12+
13+
# Rails 7 use HTML5 input type="date" by default. If input is not present fallback to plain select boxes alternative.
14+
# It's safe to use has_css? without waiting/retry. We already know field's label is visible
15+
if html5_input_field_present?(base_dom_id)
1316
fill_in options[:from], with: date
1417
else
15-
base_dom_id = get_base_dom_id_from_label_tag(options[:from])
16-
1718
find(:xpath, ".//select[@id='#{base_dom_id}_1i']").select(date.year.to_s)
1819
find(:xpath, ".//select[@id='#{base_dom_id}_2i']").select(I18n.l(date, format: '%B'))
1920
find(:xpath, ".//select[@id='#{base_dom_id}_3i']").select(date.day.to_s)
@@ -23,30 +24,43 @@ def select_date(date, options)
2324
# Select a Rails time. Options hash must include from: +label+
2425
def select_time(time, options)
2526
time = Time.zone.parse(time)
26-
if ::Rails::VERSION::MAJOR >= 7
27-
# Rails 7 generates date fields using input type="time". Capybara support's them
27+
base_dom_id = get_base_dom_from_options(options)
28+
29+
# Rails 7 use HTML5 input type="time" by default. If input is not present fallback to plain select boxes alternative.
30+
# It's safe to use has_css? without waiting/retry. We already know field's label is visible
31+
if html5_input_field_present?(base_dom_id)
2832
fill_in options[:from], with: time
2933
else
30-
base_dom_id = get_base_dom_id_from_label_tag(options[:from])
31-
3234
find(:xpath, ".//select[@id='#{base_dom_id}_4i']").select(time.hour.to_s.rjust(2, '0'))
3335
find(:xpath, ".//select[@id='#{base_dom_id}_5i']").select(time.min.to_s.rjust(2, '0'))
3436
end
3537
end
3638

3739
# Select a Rails datetime. Options hash must include from: +label+
3840
def select_datetime(datetime, options)
39-
if ::Rails::VERSION::MAJOR >= 7
40-
# Rails 7 generates datetime fields using input type="datetime-local". Capybara support's them
41+
base_dom_id = get_base_dom_id_from_label_tag(options[:from])
42+
43+
# Rails 7 use HTML5 input type="datetime-local" by default. If input is not present fallback to plain select boxes alternative.
44+
# It's safe to use has_css? without waiting/retry. We already know field's label is visible
45+
if html5_input_field_present?(base_dom_id)
4146
fill_in options[:from], with: DateTime.parse(datetime)
4247
else
43-
select_date(datetime, options)
44-
select_time(datetime, options)
48+
extended_options = options.merge(base_dom_id: base_dom_id)
49+
select_date(datetime, extended_options)
50+
select_time(datetime, extended_options)
4551
end
4652
end
4753

4854
private
4955

56+
def html5_input_field_present?(base_dom_id)
57+
::Rails::VERSION::MAJOR >= 7 && page.has_css?("##{base_dom_id}", wait: 0)
58+
end
59+
60+
def get_base_dom_from_options(options)
61+
options[:base_dom_id] || get_base_dom_id_from_label_tag(options[:from])
62+
end
63+
5064
# @example "event_starts_at_"
5165
def get_base_dom_id_from_label_tag(field)
5266
find(:xpath, ".//label[contains(., '#{field}')]")['for'].gsub(/(_[1-5]i)$/, '')

0 commit comments

Comments
 (0)