J'écris une spécification pour un contrôleur dans le projet Rails 3 en utilisant RSpec et Capybara, et je souhaite sélectionner la date actuelle dans une zone de sélection. J'ai essayé:
select Date.today, :from => 'Date of birth'
mais la spec échoue et j'obtiens une erreur:
Echec/Erreur: sélectionnez Date.aujourd'hui,: de => 'Date de naissance' NoMethodError: méthode non définie `to_xpath 'pour lun., 18 juillet 2011: Date
Comment le réparer?
P.S. Dans le fichier view, j'utilise simple_form_for tag et la zone de sélection est générée par le code:
f.input :date_of_birth
Vous devez spécifier la valeur exacte telle qu’elle se trouve dans le menu de sélection en HTML. Donc, si votre sélection a des valeurs telles que "2011/01/01", vous devez écrire:
select '2011/01/01', :from => 'Date of birth'
Votre code échoue parce que vous passez un objet de date.
Avait le même problème. J'ai googlé beaucoup et résolu de cette façon:
A écrit les macros de sélection de date dans /spec/request_macros.rb La méthode select_by_id est nécessaire pour moi, car le mois dépend de la traduction.
module RequestMacros
def select_by_id(id, options = {})
field = options[:from]
option_xpath = "//*[@id='#{field}']/option[#{id}]"
option_text = find(:xpath, option_xpath).text
select option_text, :from => field
end
def select_date(date, options = {})
field = options[:from]
select date.year.to_s, :from => "#{field}_1i"
select_by_id date.month, :from => "#{field}_2i"
select date.day.to_s, :from => "#{field}_3i"
end
end
Ajoutés à mon /spec/spec_helper.rb
config.include RequestMacros, :type => :request
Maintenant, dans mes tests d'intégration dans spec/request je peux utiliser
select_date attr[:birthday], :from => "user_birthday"
Merci à http://jasonneylon.wordpress.com/2011/02/16/selecting-from-a-dropdown-generically-with-capybara/ et https://Gist.github.com/558786 :)
grâce au mérite de Markus Hartmair pour une excellente solution, je préfère utiliser les étiquettes comme sélecteurs en raison de la lisibilité améliorée. Donc, ma version de son module d'assistance est:
module SelectDateHelper
def select_date(date, options = {})
field = options[:from]
base_id = find(:xpath, ".//label[contains(.,'#{field}')]")[:for]
year, month, day = date.split(',')
select year, :from => "#{base_id}_1i"
select month, :from => "#{base_id}_2i"
select day, :from => "#{base_id}_3i"
end
end
appelez ça comme ça:
select_date "2012,Jan,1", :from => "From date"
Une légère adaptation de la réponse de Markus:
def select_date(date, options = {})
raise ArgumentError, 'from is a required option' if options[:from].blank?
field = options[:from].to_s
select date.year.to_s, :from => "#{field}_1i"
select Date::MONTHNAMES[date.month], :from => "#{field}_2i"
select date.day.to_s, :from => "#{field}_3i"
end
J'ai trouvé une solution propre pour que rspec et capybara testent à l'aide de méthodes de sélection de date et d'heure, où, dans votre code HTML, vous utilisez une sélection de date/heure ou une sélection de date. Cela fonctionne avec Rails 4, RSpec 3.1 et Capybara 2.4.4.
Dites dans votre formulaire HTML que vous avez les éléments suivants:
<%= f.datetime_select(:start_date, {default: DateTime.now, Prompt: {day: 'Choose day', month: "Choose month", year: "Choose year"}}, {class: "date-select"}) %>
l'assistant de sélection de la date et de l'heure crée 5 champs de sélection avec des identifiants tels que id="modelname_start_date_1i"
, auquel l'identifiant est ajouté avec 1i, 2i, 3i, 4i, 5i. Par défaut, Année, Mois, Jour, Heure, Minute. Si vous modifiez l'ordre des champs, veillez à modifier l'auxiliaire de fonctionnalité ci-dessous.
1) Créer un assistant de fonctionnalité pour les aides de dates et d’heures
spec/support/helpers/date_time_select_helpers.rb
module Features
module DateTimeSelectHelpers
def select_date_and_time(date, options = {})
field = options[:from]
select date.strftime('%Y'), :from => "#{field}_1i" #year
select date.strftime('%B'), :from => "#{field}_2i" #month
select date.strftime('%-d'), :from => "#{field}_3i" #day
select date.strftime('%H'), :from => "#{field}_4i" #hour
select date.strftime('%M'), :from => "#{field}_5i" #minute
end
def select_date(date, options = {})
field = options[:from]
select date.strftime('%Y'), :from => "#{field}_1i" #year
select date.strftime('%B'), :from => "#{field}_2i" #month
select date.strftime('%-d'), :from => "#{field}_3i" #day
end
end
end
Notez que pour le jour où j’utilise %-d
, il vous donne une valeur numérique non complétée (c’est-à-dire 4) au lieu de %d
qui a une valeur numérique complétée par un zéro (c.-à-d. 04). Vérifiez les formats de date avec strftime
2) Vous devez ensuite inclure vos méthodes helpers date et heure dans spec/support/helpers.rb pour pouvoir les utiliser dans n’importe quel fichier de spécification.
require 'support/helpers/date_time_select_helpers'
RSpec.configure do |config|
config.include Features::DateTimeSelectHelpers, type: :feature
end
3) Dans votre fichier Spec, vous pouvez appeler votre assistant. Par exemple:
feature 'New Post' do
scenario 'Add a post' do
visit new_post_path
fill_in "post[name]", with: "My post"
select_date_and_time(2.days.from_now, from:"post_start_date")
click_button "Submit"
expect(page).to have_content "Your post was successfully saved"
end
end
Merci à Dylan de l'avoir signalé, mais au cas où quelqu'un chercherait la version concombre, vous pouvez l'utiliser:
select_date("Date of birth", :with => "1/1/2011")
Pour plus d'informations, voir select_date .
Dans ma situation particulière, j'ajoute potentiellement plusieurs champs de sélection de date à la page avec la fonctionnalité accepts_nested_attributes_for
. Cela signifie que je ne suis pas sûr de ce que seront les noms complets id
ou name
des champs.
Voici la solution que j'ai trouvée au cas où cela pourrait aider quelqu'un d'autre à googler ceci:
J'emballe le champ de sélection de date dans un conteneur div avec une classe:
<div class='date-of-birth-container'>
<%= f.date_select :date_of_birth %>
</div>
Puis dans mes spécifications techniques:
within '.date-of-birth-container' do
find("option[value='1']", text: 'January').select_option
find("option[value='1']", text: '1').select_option
find("option[value='1955']").select_option
end
Voici une méthode d'assistance que j'ai écrite pour cela:
def select_date_within_css_selector(date, css_selector)
month_name = Date::MONTHNAMES.fetch(date.month)
within css_selector do
find("option[value='#{date.month}']", text: month_name).select_option
find("option[value='#{date.day}']", text: date.day.to_s).select_option
find("option[value='#{date.year}']").select_option
end
end
Ensuite, en utilisant l'assistant:
select_date_within_css_selector(Date.new(1955, 1, 1), '.date-of-birth-container')
Compte tenu du code Formtastic suivant, le sélecteur de date par défaut de Rails est rendu:
= f.input :born_on, end_year: Time.now.year, start_year: 60.years.ago.year
Dans vos spécifications, divisez la date en appels séparés pour chaque balise de sélection:
select '1956', from: 'person_born_on_1i'
select 'July', from: 'person_born_on_2i'
select '9', from: 'person_born_on_3i'
Je n'aime pas que ce code connaisse si bien le code HTML, mais il fonctionne avec les versions de gems pour le moment.
Gemmes:
Ce qui suit a fonctionné pour moi, en utilisant un champ date_field:
fill_in "Date", with: DateTime.now.strftime('%m/%d/%Y')
Pour Rails 4 , au cas où quelqu'un arriverait à cette question sans se limiter à Rails 3.
select '2020', from: 'field_name_{}_1i'
select 'January', from: 'field_name_{}_2i'
select '1', from: 'field_name_{}_3i'
Vous pouvez bien sûr extraire ceci dans un assistant et le rendre dynamique.