用Javascript(Rspec,Spork和FactoryGirl引导)的水豚

时间:2012-03-14 01:07:11

标签: ruby-on-rails database rspec capybara spork

我有一个异步的javascript函数,我需要用capybara进行测试。我知道我必须在测试中使用js: true选项并设置config.use_transactional_fixtures = false,然后输入一些database_cleaner,但我仍然无法使其正常工作。

cart_spec贯穿整个过程,将项目添加到购物车并购买(因此它嵌套得非常深)。

checkout.html.erb使用stripe库来处理信用卡。这有我需要测试的javascript功能。

当我使用js: true选项运行测试时,我发现sports_url上没有“添加到购物车”的测试失败,表示未将运动保存到数据库中。

当我在没有js: true选项的情况下运行测试时,除了it "should warn user that cc number is invalid" do之外,所有测试都通过,因为这是javascript所在的位置。

我正在运行spork,并尝试重新启动服务器。

修改

问题是我的测试是在www.example.com域运行,因此我的sports_url会被定向到www.example.com/sports。我问过一个新问题here。如果我使用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 :(得分:0)

很难给出确切的答案。

当您运行JS规范时,有2个进程。当你在并行过程中访问页面时,你可能没有保存记录。

  1. 尝试等待@sport保存到数据库中。 添加
  2. wait_until { page.has_content? "Add to Cart" }

    之前

    click_link "Add to Cart"

    Capybara将等待这些话(最多2秒)。要增加默认等待时间,请将Capybara.default_wait_time = 5添加到spec_helper。

    1. 确保DatabaseCleaner策略确实是:truncation。我看到你的spec_helper。检查两次:)

答案 1 :(得分:0)

问题是我使用的是visit <route>_url。 rails测试的默认域名是exmaple.com,因此我的浏览器尝试访问www.example.com/sports,这是由国际互联网命名委员会保留的。

我将这些更改为visit <route>_path,事情很有效。