Капибара с Javascript (Rspec, Spork и FactoryGirl для загрузки) - PullRequest
4 голосов
/ 14 марта 2012

У меня есть асинхронная функция JavaScript, которую нужно протестировать с капибарой. Я понимаю, что должен использовать опцию js: true в тестах и ​​установить config.use_transactional_fixtures = false, затем добавить database_cleaner, но все равно не могу заставить его работать.

cart_spec проходит через весь процесс добавления товара в корзину и его покупки (так что он вложен довольно глубоко).

checkout.html.erb использует библиотеку stripe для обработки кредитных карт. Это имеет функциональность javascript, которую я должен проверить.

Когда я запускаю тесты с опцией js: true, я получаю тестовый сбой, который не существует в «1014 *», что указывает на то, что виды спорта не сохраняются в базе данных.

Когда я запускаю тесты без опции js: true, все тесты проходят, кроме it "should warn user that cc number is invalid" do, потому что именно там находится javascript.

Я использую spork и попытался перезапустить сервер.

Редактировать

Проблема в том, что мой тест выполняется на домене www.example.com, поэтому мой sports_url направляется на www.example.com/sports. Я задал новый вопрос здесь . Если я получу к нему доступ с помощью sports_path, он прекрасно работает.

Вот файлы:

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

Ответы [ 2 ]

0 голосов
/ 15 марта 2012

Проблема была в том, что я использовал visit <route>_url. Домен по умолчанию для тестов rails - exmaple.com, поэтому мой браузер пытался получить доступ к www.example.com/sports, который любезно зарезервирован международным комитетом по присвоению имен в Интернете.

Я изменил их на visit <route>_path, и все отлично работает.

0 голосов
/ 14 марта 2012

Трудно дать вам точный ответ.

Когда вы запускаете спецификации JS, есть 2 процесса.И возможно, что запись не сохраняется, когда вы посещаете страницу в параллельном процессе.

  1. Попробуйте подождать, пока @sport будет сохранен в БД.Добавьте

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

до

click_link "Add to Cart"

Капибара будет ждать этих слов (максимум 2 секунды).Чтобы увеличить время ожидания по умолчанию, добавьте Capybara.default_wait_time = 5 в spec_helper.

  1. Убедитесь, что стратегия DatabaseCleaner действительно :truncation.Я вижу ваш spec_helper.Просто проверьте это дважды:)
...