4

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

cart_spec贯穿将商品添加到购物车并购买它的整个过程(因此它嵌套得很深)。

checkout.html.erb使用stripe图书馆处理信用卡。它具有我需要测试的 javascript 功能。

当我使用该js: true选项运行测试时,我得到一个测试失败,表明 'Add to Cart' 上不存在,这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。我在这里问了一个新问题。如果我使用它访问它sports_path,它会很好用。

以下是文件:

购物车规格:

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>

规范助手:

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

2 回答 2

0

很难给你确切的答案。

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

  1. 尝试等到@sport 保存到数据库中。添加

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。只需检查两次:)
于 2012-03-14T01:49:45.767 回答
0

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

我将它们更改为visit <route>_path并且效果很好。

于 2012-03-15T16:37:15.717 回答