Capybara + Remote Request

I have a form that I am testing with Capybara. This form URL refers to my Braintree sandbox, although I suspect that a problem will occur for any remote URL. When Capybara clicks the submit button for the form, the request is routed to the dummy application, not the remote service.

Here is an example application that reproduces this problem: https://github.com/radar/capybara_remote . Run the exec ruby ​​test / form_test.rb command and the test will pass, which I usually did not expect.

Why is this happening and is this behavior that I can rely on that always happens?

+5
source share
1 answer

Capybara:

, RackTest URL- (, , API- OAuth), .

, , . :

// node/actions.rb

def click_button(locator)
  find(:button, locator).click
end

find, . . :

// node/element.rb

def click
  wait_until { base.click }
end

, base, , lib/capybara/rack_test/node.rb lib/capybara/selenium/node.rb. Rack::Test, Selenium, , , :

//rack_test/ node.rb

def click
  if tag_name == 'a'
    method = self["data-method"] if driver.options[:respect_data_method]
    method ||= :get
    driver.follow(method, self[:href].to_s)
  elsif (tag_name == 'input' and %w(submit image).include?(type)) or
    ((tag_name == 'button') and type.nil? or type == "submit")
    Capybara::RackTest::Form.new(driver, form).submit(self)
  end
end

tag_name, , - , , elsif. input type == "submit", , Capybara::RackTest::Form:

//rack_test/form.rb

def submit(button)
  driver.submit(method, native['action'].to_s, params(button))
end

, . driver, , Rack::Test Capybara. ?

//rack_test/driver.rb

def submit(method, path, attributes)
  browser.submit(method, path, attributes)
end

? , , :

def browser
  @browser ||= Capybara::RackTest::Browser.new(self)
end

, submit.

//rack_test/browser.rb

def submit(method, path, attributes)
  path = request_path if not path or path.empty?
  process_and_follow_redirects(method, path, attributes, {'HTTP_REFERER' => current_url})
end

process_and_follow_redirects , :

def process_and_follow_redirects(method, path, attributes = {}, env = {})
  process(method, path, attributes, env)
  5.times do
    process(:get, last_response["Location"], {}, env) if last_response.redirect?
  end
  raise Capybara::InfiniteRedirectError, "redirected more than 5 times, check for infinite redirects." if last_response.redirect?
end

, process:

def process(method, path, attributes = {}, env = {})
  new_uri = URI.parse(path)
  method.downcase! unless method.is_a? Symbol

  if new_uri.host
    @current_host = "#{new_uri.scheme}://#{new_uri.host}"
    @current_host << ":#{new_uri.port}" if new_uri.port != new_uri.default_port
  end

  if new_uri.relative?
    if path.start_with?('?')
      path = request_path + path
    elsif not path.start_with?('/')
      path = request_path.sub(%r(/[^/]*$), '/') + path
    end
    path = current_host + path
  end

  reset_cache!
  send(method, path, attributes, env.merge(options[:headers] || {}))
end

, method. binding.pry require 'pry' . , method :post, , , new_uri URI URL- .

post? method(:post).source_location :

["/Users/ryan/.rbenv/versions/1.9.3-p374/lib/ruby/1.9.1/forwardable.rb", 199]

... Capybara def post -?

capybara (master)★ack "def post"
lib/capybara/rack_test/driver.rb
76:  def post(*args, &block); browser.post(*args, &block); end

. , browser is a Capybara:: RackTest:: Browser`. :

class Capybara::RackTest::Browser
  include ::Rack::Test::Methods

, Rack::Test::Methods post. .

//test.rb

def post(uri, params = {}, env = {}, &block)
  env = env_for(uri, env.merge(:method => "POST", :params => params))
  process_request(uri, env, &block)
end

env_for , process_request?

//test.rb

def process_request(uri, env)
  uri = URI.parse(uri)
  uri.host ||= @default_host

  @rack_mock_session.request(uri, env)

  if retry_with_digest_auth?(env)
    auth_env = env.merge({
      "HTTP_AUTHORIZATION"          => digest_auth_header,
      "rack-test.digest_auth_retry" => true
    })
    auth_env.delete('rack.request')
    process_request(uri.path, auth_env)
  else
    yield last_response if block_given?

    last_response
  end
end

, @rack_mock_session . ?

rack-test (master)★ack "@rack_mock_session ="
lib/rack/test.rb
40:          @rack_mock_session = mock_session
42:          @rack_mock_session = MockSession.new(mock_session)

, . ?

def initialize(mock_session)
  @headers = {}

  if mock_session.is_a?(MockSession)
    @rack_mock_session = mock_session
  else
    @rack_mock_session = MockSession.new(mock_session)
  end

  @default_host = @rack_mock_session.default_host
end

, , MockSession. MockSession request?

def request(uri, env)
  env["HTTP_COOKIE"] ||= cookie_jar.for(uri)
  @last_request = Rack::Request.new(env)
  status, headers, body = @app.call(@last_request.env)
  headers["Referer"] = env["HTTP_REFERER"] || ""

  @last_response = MockResponse.new(status, headers, body, env["rack.errors"].flush)
  body.close if body.respond_to?(:close)

  cookie_jar.merge(last_response.headers["Set-Cookie"], uri)

  @after_request.each { |hook| hook.call }

  if @last_response.respond_to?(:finish)
    @last_response.finish
  else
    @last_response
  end
end

, @app - . call, , .

, , .

+10

All Articles