web-dev-qa-db-fra.com

Comment sélectionner une date dans une zone de sélection en utilisant Capybara dans Rails 3?

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
22
Aleksandr Shvalev

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.

21
solnic

Avait le même problème. J'ai googlé beaucoup et résolu de cette façon:

  1. 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
    
  2. 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 :)

24
Markus Hartmair

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"
9
Les Nightingill

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
7
Kris

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
7

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 .

2
Jaryl

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')
1
Elliot Larson

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:

  • Capybara 2.1.0
  • Formtastic 2.2.1
  • Rails 3.2.13
  • RSpec 2.13.0
1
scarver2

Ce qui suit a fonctionné pour moi, en utilisant un champ date_field:

fill_in "Date", with: DateTime.now.strftime('%m/%d/%Y')
0
npostolovski

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.

0