50 votes

Capybara avec :js => true fait échouer le test

Je suis novice en matière de Capybara et de tests sur Rails en général, alors pardonnez-moi si la réponse est simple.

J'ai ce test

it "should be able to edit an assignment" do
    visit dashboard_path
    select(@project.client + " - " + @project.name, :from => "assignment_project_id")
    select(@team_member.first_name + " " + @team_member.last_name, :from => "assignment_person_id")
    click_button "Create assignment"
    page.should have_content(@team_member.first_name)
end

il passe tel quel, mais si j'ajoute :js => true il échoue avec

cannot select option, no option with text 'Test client - Test project' in select box 'assignment_project_id'

J'utilise FactoryGirl pour créer les données, et comme le test passe sans JS, je sais que cette partie fonctionne.

J'ai essayé avec le pilote JS par défaut et avec le pilote :webkit (avec capybara-webkit installé).

Je suppose que je ne comprends pas assez ce que fait l'activation de JS pour Capybara.

Pourquoi le test échouerait-il avec JS activé ?

107voto

brutuscat Points 1912

J'ai lu le fichier readme de Capybara à l'adresse suivante https://github.com/jnicklas/capybara et cela a résolu mon problème.

Les fixtures transactionnelles ne fonctionnent que dans le pilote Rack::Test par défaut, mais pas pour d'autres pilotes comme Selenium. Cucumber s'en occupe automatiquement, mais avec Test::Unit ou RSpec, vous devrez peut-être utiliser la gemme database_cleaner gem. Voir cette explication (et le code pour solution 2 y solution 3 ) pour plus de détails.

Mais en fait, il s'agit d'un problème de threading qui implique que Capybara a son propre thread lorsqu'il exécute le pilote non-Rack, ce qui permet à la fonction de fixation transactionnelle d'utiliser une deuxième connexion dans un autre contexte. Ainsi, le thread du pilote n'est jamais dans le même contexte que le rspec en cours d'exécution.

Heureusement, cela peut être facilement résolu (du moins pour moi) en faisant un changement dynamique dans la stratégie DatabaseCleaner à utiliser :

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.before :each do
    if Capybara.current_driver == :rack_test
      DatabaseCleaner.strategy = :transaction
    else
      DatabaseCleaner.strategy = :truncation
    end
    DatabaseCleaner.start
  end

  config.after do
    DatabaseCleaner.clean
  end
end

9voto

Aidan Feldman Points 981

Une variante de La réponse de brutuscat qui a corrigé nos spécifications de fonctionnalités (qui utilisent toutes Capybara) :

config.before(:suite) do
  DatabaseCleaner.clean_with(:truncation)
end

config.before(:each) do
  # set the default
  DatabaseCleaner.strategy = :transaction
end

config.before(:each, type: :feature) do
  DatabaseCleaner.strategy = :truncation
end

config.before(:each) do
  DatabaseCleaner.start
end

config.append_after(:each) do
  DatabaseCleaner.clean
end

7voto

Il existe une autre façon de traiter ce problème, décrite et discutée ici : Pourquoi ne pas utiliser des connexions ActiveRecord partagées pour Rspec + Selenium ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X