Capybara with Javascript (Rspec, Spork and FactoryGirl for download)

I have an asynchronous javascript function that I need to test with capybara. I understand that I need to use the js: true parameter for tests and set config.use_transactional_fixtures = false and then insert database_cleaner , but I still can't get it to work.

cart_spec goes through the whole process of adding an item to the cart and buying it (therefore, it is nested quite deeply).

checkout.html.erb uses the stripe library to process credit cards. I have a javascript function that I need to check.

When I run tests with the js: true option, I get a verification error that "Add to Cart" does not exist on sports_url , which indicates that the sport is not stored in the database.

When I run tests without the js: true option, all tests pass except for it "should warn user that cc number is invalid" do , because that is where javascript is located.

I run spork and tried to restart the server.

Edit

The problem is that my test runs on the domain www.example.com, so my sports_url routed to www.example.com/sports. I asked a new question here . If I access it using sports_path , it works fine.

Here are the files:

cart_spec:

 require "spec_helper" describe "Cart" do before do @user = FactoryGirl.create(:user) @cart = @user.carts.create! end describe "using stripe" do before do @sport = FactoryGirl.create(:sport) end describe "user adds sport to cart", js: true do before do visit sports_url click_link "Add to Cart" end it "should be checkout page" do page.should have_content("Total") end describe "user clicks checkout" do before do click_button "Checkout" end it "should redirect user to sign in form" do page.should have_selector('h2', text: "Sign in") end describe "user logs on" do before do fill_in "Email", with: @user.email fill_in "Password", with: @user.password click_button "Sign in" end it "should be on checkout page" do page.should have_selector('h2', text: "Checkout") end describe "user fills in form" do context "with invalid cc number" do before do fill_in "card-number", with: 42 click_button "Submit Payment" end it "should warn user that cc number is invalid" do page.should have_content("Your card number is invalid") end end end end end end end describe "GET /carts/checkout" do subject { @cart } it { should respond_to(:paypal_url) } it { should respond_to(:apply_discount) } it "paypal_url contains notification" do @cart.paypal_url(root_url, payment_notifications_url).should include("&notify_url=http%3A%2F%2Fwww.example.com%2Fpayment_notifications") end it "paypal_url contains invoice id" do @cart.paypal_url(root_url, payment_notifications_url).should match /&invoice=\d+&/ end it "paypal_url contains return url" do @cart.paypal_url(root_url, payment_notifications_url).should include("&return=http%3A%2F%2Fwww.example.com") end end describe "GET /carts/discount" do it "should apply discount to all line items" do @cart.line_items.build(:unit_price => 48) @cart.apply_discount @cart.line_items.each do |lineItem| lineItem.unit_price.should == 9.99 end end end end 

checkout.html.erb:

 <h2>Checkout</h2> <span class="payment-errors"></span> <form action="" method="POST" id="payment-form"> <div class="form-row"> <label>Card Number</label> <input type="text" size="20" autocomplete="off" id ="card-number" class="card-number"/> </div> <div class="form-row"> <label>CVC</label> <input type="text" size="4" autocomplete="off" class="card-cvc"/> </div> <div class="form-row"> <label>Expiration (MM/YYYY)</label> <input type="text" size="2" class="card-expiry-month"/> <span> / </span> <input type="text" size="4" class="card-expiry-year"/> </div> <button type="submit" class="submit-button">Submit Payment</button> </form> <script type="text/javascript" src="https://js.stripe.com/v1/"></script> <script type="text/javascript"> Stripe.setPublishableKey('pk_xIm00GVAKVLMWmfeR2J8GlmeHcyhL'); $(document).ready(function() { $("#payment-form").submit(function(event) { // disable the submit button to prevent repeated clicks $('.submit-button').attr("disabled", "disabled"); Stripe.createToken({ number: $('.card-number').val(), cvc: $('.card-cvc').val(), exp_month: $('.card-expiry-month').val(), exp_year: $('.card-expiry-year').val() }, stripeResponseHandler); // prevent the form from submitting with the default action return false; }); }); function stripeResponseHandler(status, response) { if (response.error) { $('.submit-button').removeAttr("disabled"); //show the errors on the form $(".payment-errors").html(response.error.message); } else { var form$ = $("#payment-form"); // token contains id, last4, and card type var token = response['id']; // insert the token into the form so it gets submitted to the server form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>"); // and submit form$.get(0).submit(); } } </script> 

spec_helper:

 require 'rubygems' require 'spork' Spork.prefork do # Loading more in this block will cause your tests to run faster. However, # if you change any configuration or code from libraries loaded here, you'll # need to restart spork for it take effect. # This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] ||= 'test' require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' require 'rspec/autorun' # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} RSpec.configure do |config| # == Mock Framework # # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: # # config.mock_with :mocha # config.mock_with :flexmock # config.mock_with :rr config.mock_with :rspec # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false # instead of true. config.use_transactional_fixtures = false # If true, the base class of anonymous controllers will be inferred # automatically. This will be the default behavior in future versions of # rspec-rails. config.infer_base_class_for_anonymous_controllers = false config.before(:suite) do DatabaseCleaner.strategy = :truncation end config.before(:each) do DatabaseCleaner.start end config.after(:each) do DatabaseCleaner.clean end end end Spork.each_run do # This code will be run each time you run your specs. end 
+4
source share
2 answers

The problem was using visit <route>_url . The default domain for rails tests is exmaple.com, so my browser tried to access www.example.com/sports , which is kindly reserved by the international internet naming committee.

I changed them to visit <route>_path and everything works fine.

0
source

It is hard to give you an accurate answer.

When you use JS specifications, there are 2 processes. And it is possible that the record is not saved, t, when you visit the page in a parallel process.

  • Try to wait until @sport is saved to the database. Add

wait_until { page.has_content? "Add to Cart" }

before

click_link "Add to Cart"

Capybara will wait for these words (maximum 2 seconds). To increase the default timeout, add Capybara.default_wait_time = 5 to spec_helper.

  • Make sure the DatabaseCleaner strategy is valid :truncation . I see your spec_helper. Just check it twice :)
0
source

Source: https://habr.com/ru/post/1401283/


All Articles