class Rack::Test::Session

This class represents a series of requests issued to a Rack app, sharing a single cookie jar

Rack::Test::Session's methods are most often called through Rack::Test::Methods, which will automatically build a session when it's first used.

Public Class Methods

new(mock_session) click to toggle source

Creates a Rack::Test::Session for a given Rack app or Rack::MockSession.

Note: Generally, you won't need to initialize a Rack::Test::Session directly. Instead, you should include Rack::Test::Methods into your testing context. (See README.rdoc for an example)

# File lib/rack/test.rb, line 35
def initialize(mock_session)
  @headers = {}
  @env = {}
  @digest_username = nil
  @digest_password = nil

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

  @default_host = @rack_mock_session.default_host
end

Public Instance Methods

authorize(username, password)
Alias for: basic_authorize
basic_authorize(username, password) click to toggle source

Set the username and password for HTTP Basic authorization, to be included in subsequent requests in the HTTP_AUTHORIZATION header.

Example:

basic_authorize "bryan", "secret"
# File lib/rack/test.rb, line 166
def basic_authorize(username, password)
  encoded_login = ["#{username}:#{password}"].pack('m0')
  header('Authorization', "Basic #{encoded_login}")
end
Also aliased as: authorize
custom_request(verb, uri, params = {}, env = {}, &block) click to toggle source

Issue a request using the given verb for the given URI. See get

Example:

custom_request "LINK", "/"
# File lib/rack/test.rb, line 126
def custom_request(verb, uri, params = {}, env = {}, &block)
  uri = parse_uri(uri, env)
  env = env_for(uri, env.merge(method: verb.to_s.upcase, params: params))
  process_request(uri, env, &block)
end
delete(uri, params = {}, env = {}, &block) click to toggle source

Issue a DELETE request for the given URI. See get

Example:

delete "/"
# File lib/rack/test.rb, line 89
def delete(uri, params = {}, env = {}, &block)
  custom_request('DELETE', uri, params, env, &block)
end
digest_authorize(username, password) click to toggle source

Set the username and password for HTTP Digest authorization, to be included in subsequent requests in the HTTP_AUTHORIZATION header.

Example:

digest_authorize "bryan", "secret"
# File lib/rack/test.rb, line 178
def digest_authorize(username, password)
  @digest_username = username
  @digest_password = password
end
env(name, value) click to toggle source

Set an env var to be included on all subsequent requests through the session. Use a value of nil to remove a previously configured env.

Example:

env "rack.session", {:csrf => 'token'}
# File lib/rack/test.rb, line 153
def env(name, value)
  if value.nil?
    @env.delete(name)
  else
    @env[name] = value
  end
end
follow_redirect!() click to toggle source

Rack::Test will not follow any redirects automatically. This method will follow the redirect returned (including setting the Referer header on the new request) in the last response. If the last response was not a redirect, an error will be raised.

# File lib/rack/test.rb, line 187
def follow_redirect!
  unless last_response.redirect?
    raise Error, 'Last response was not a redirect. Cannot follow_redirect!'
  end
  request_method, params =
    if last_response.status == 307
      [last_request.request_method.downcase.to_sym, last_request.params]
    else
      [:get, {}]
    end

  # Compute the next location by appending the location header with the
  # last request, as per https://tools.ietf.org/html/rfc7231#section-7.1.2
  # Adding two absolute locations returns the right-hand location
  next_location = URI.parse(last_request.url) + URI.parse(last_response['Location'])

  send(
    request_method, next_location.to_s, params,
    'HTTP_REFERER' => last_request.url,
    'rack.session' => last_request.session,
    'rack.session.options' => last_request.session_options
  )
end
get(uri, params = {}, env = {}, &block) click to toggle source

Issue a GET request for the given URI with the given params and Rack environment. Stores the issues request object in last_request and the app's response in last_response. Yield last_response to a block if given.

Example:

get "/"
# File lib/rack/test.rb, line 57
def get(uri, params = {}, env = {}, &block)
  custom_request('GET', uri, params, env, &block)
end
head(uri, params = {}, env = {}, &block) click to toggle source

Issue a HEAD request for the given URI. See get

Example:

head "/"
# File lib/rack/test.rb, line 105
def head(uri, params = {}, env = {}, &block)
  custom_request('HEAD', uri, params, env, &block)
end
header(name, value) click to toggle source

Set a header to be included on all subsequent requests through the session. Use a value of nil to remove a previously configured header.

In accordance with the Rack spec, headers will be included in the Rack environment hash in HTTP_USER_AGENT form.

Example:

header "User-Agent", "Firefox"
# File lib/rack/test.rb, line 140
def header(name, value)
  if value.nil?
    @headers.delete(name)
  else
    @headers[name] = value
  end
end
options(uri, params = {}, env = {}, &block) click to toggle source

Issue an OPTIONS request for the given URI. See get

Example:

options "/"
# File lib/rack/test.rb, line 97
def options(uri, params = {}, env = {}, &block)
  custom_request('OPTIONS', uri, params, env, &block)
end
patch(uri, params = {}, env = {}, &block) click to toggle source

Issue a PATCH request for the given URI. See get

Example:

patch "/"
# File lib/rack/test.rb, line 81
def patch(uri, params = {}, env = {}, &block)
  custom_request('PATCH', uri, params, env, &block)
end
post(uri, params = {}, env = {}, &block) click to toggle source

Issue a POST request for the given URI. See get

Example:

post "/signup", "name" => "Bryan"
# File lib/rack/test.rb, line 65
def post(uri, params = {}, env = {}, &block)
  custom_request('POST', uri, params, env, &block)
end
put(uri, params = {}, env = {}, &block) click to toggle source

Issue a PUT request for the given URI. See get

Example:

put "/"
# File lib/rack/test.rb, line 73
def put(uri, params = {}, env = {}, &block)
  custom_request('PUT', uri, params, env, &block)
end
request(uri, env = {}, &block) click to toggle source

Issue a request to the Rack app for the given URI and optional Rack environment. Stores the issues request object in last_request and the app's response in last_response. Yield last_response to a block if given.

Example:

request "/"
# File lib/rack/test.rb, line 116
def request(uri, env = {}, &block)
  uri = parse_uri(uri, env)
  env = env_for(uri, env)
  process_request(uri, env, &block)
end

Private Instance Methods

default_env() click to toggle source
# File lib/rack/test.rb, line 305
def default_env
  { 'rack.test' => true, 'REMOTE_ADDR' => '127.0.0.1' }.merge(@env).merge(headers_for_env)
end
digest_auth_configured?() click to toggle source
# File lib/rack/test.rb, line 301
def digest_auth_configured?
  @digest_username
end
digest_auth_header() click to toggle source
# File lib/rack/test.rb, line 280
def digest_auth_header
  challenge = last_response['WWW-Authenticate'].split(' ', 2).last
  params = Rack::Auth::Digest::Params.parse(challenge)

  params.merge!('username' => @digest_username,
                'nc'        => '00000001',
                'cnonce'    => 'nonsensenonce',
                'uri'       => last_request.fullpath,
                'method'    => last_request.env['REQUEST_METHOD'])

  params['response'] = MockDigestRequest.new(params).response(@digest_password)

  "Digest #{params}"
end
env_for(uri, env) click to toggle source
# File lib/rack/test.rb, line 221
def env_for(uri, env)
  env = default_env.merge(env)

  env['HTTP_HOST'] ||= [uri.host, (uri.port if uri.port != uri.default_port)].compact.join(':')

  env.update('HTTPS' => 'on') if URI::HTTPS === uri
  env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' if env[:xhr]

  # TODO: Remove this after Rack 1.1 has been released.
  # Stringifying and upcasing methods has be commit upstream
  env['REQUEST_METHOD'] ||= env[:method] ? env[:method].to_s.upcase : 'GET'

  params = env.delete(:params) do {} end

  if env['REQUEST_METHOD'] == 'GET'
    # merge :params with the query string
    if params
      params = parse_nested_query(params) if params.is_a?(String)

      uri.query = [uri.query, build_nested_query(params)].compact.reject { |v| v == '' }.join('&')
    end
  elsif !env.key?(:input)
    env['CONTENT_TYPE'] ||= 'application/x-www-form-urlencoded'

    if params.is_a?(Hash)
      if data = build_multipart(params)
        env[:input] = data
        env['CONTENT_LENGTH'] ||= data.length.to_s
        env['CONTENT_TYPE'] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
      else
        # NB: We do not need to set CONTENT_LENGTH here;
        # Rack::ContentLength will determine it automatically.
        env[:input] = params_to_string(params)
      end
    else
      env[:input] = params
    end
  end

  set_cookie(env.delete(:cookie), uri) if env.key?(:cookie)

  Rack::MockRequest.env_for(uri.to_s, env)
end
headers_for_env() click to toggle source
# File lib/rack/test.rb, line 309
def headers_for_env
  converted_headers = {}

  @headers.each do |name, value|
    env_key = name.upcase.tr('-', '_')
    env_key = 'HTTP_' + env_key unless env_key == 'CONTENT_TYPE'
    converted_headers[env_key] = value
  end

  converted_headers
end
params_to_string(params) click to toggle source
# File lib/rack/test.rb, line 321
def params_to_string(params)
  case params
  when Hash then build_nested_query(params)
  when nil  then ''
  else params
  end
end
parse_uri(path, env) click to toggle source
# File lib/rack/test.rb, line 213
def parse_uri(path, env)
  URI.parse(path).tap do |uri|
    uri.path = "/#{uri.path}" unless uri.path[0] == '/'
    uri.host ||= @default_host
    uri.scheme ||= 'https' if env['HTTPS'] == 'on'
  end
end
process_request(uri, env) { |last_response| ... } click to toggle source
# File lib/rack/test.rb, line 265
def process_request(uri, env)
  @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
retry_with_digest_auth?(env) click to toggle source
# File lib/rack/test.rb, line 295
def retry_with_digest_auth?(env)
  last_response.status == 401 &&
    digest_auth_configured? &&
    !env['rack-test.digest_auth_retry']
end