Module: Crspec::Rails::RequestHelpers

Includes:
ActiveSupport::Testing::Assertions, ActiveSupport::Testing::FileFixtures, ActiveSupport::Testing::TimeHelpers
Defined in:
lib/crspec/rails/request_helpers.rb

Defined Under Namespace

Classes: ResponseStruct

Instance Method Summary collapse

Instance Method Details

#delete(path, params: {}, headers: {}) ⇒ Object



147
148
149
# File 'lib/crspec/rails/request_helpers.rb', line 147

def delete(path, params: {}, headers: {})
  process_request(:delete, path, params, headers)
end

#get(path, params: {}, headers: {}) ⇒ Object



131
132
133
# File 'lib/crspec/rails/request_helpers.rb', line 131

def get(path, params: {}, headers: {})
  process_request(:get, path, params, headers)
end

#json_responseObject



45
46
47
48
49
50
# File 'lib/crspec/rails/request_helpers.rb', line 45

def json_response
  return nil unless response&.body
  JSON.parse(response.body, symbolize_names: true)
rescue JSON::ParserError
  nil
end

#patch(path, params: {}, headers: {}) ⇒ Object



143
144
145
# File 'lib/crspec/rails/request_helpers.rb', line 143

def patch(path, params: {}, headers: {})
  process_request(:patch, path, params, headers)
end

#post(path, params: {}, headers: {}) ⇒ Object



135
136
137
# File 'lib/crspec/rails/request_helpers.rb', line 135

def post(path, params: {}, headers: {})
  process_request(:post, path, params, headers)
end

#process_request(method, path, params = {}, headers = {}) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/crspec/rails/request_helpers.rb', line 52

def process_request(method, path, params = {}, headers = {})
  # Emulate Rails integration test semantics:
  # - For GET/DELETE, params are typically carried in the query string
  # - For POST/PUT/PATCH with JSON, params are in the request body
  # - `format: :json` should affect the requested path / Accept header

  params = params.dup if params.is_a?(Hash)

  requested_format = nil
  if params.is_a?(Hash) && params.key?(:format)
    requested_format = params.delete(:format)&.to_s
  end

  path_with_format = path.dup
  if requested_format && !path_with_format.end_with?(".#{requested_format}")
    path_with_format = "#{path_with_format}.#{requested_format}"
  end

  query_string = nil
  body_string = ""

  if params.is_a?(Hash) && !params.empty?
    if %i[get delete].include?(method.to_sym)
      # Attach params as query string for idempotent verbs
      query_string = URI.encode_www_form(params)
    else
      # Default to JSON body for non-GET verbs when params are present
      body_string = params.to_json
      headers = headers.merge("CONTENT_TYPE" => "application/json") unless headers["CONTENT_TYPE"]
    end
  elsif params.is_a?(String)
    body_string = params
  end

  env = {
    "REQUEST_METHOD" => method.to_s.upcase,
    "PATH_INFO" => path_with_format,
    "QUERY_STRING" => query_string.to_s,
    "rack.input" => StringIO.new(body_string),
    "CONTENT_TYPE" => headers["CONTENT_TYPE"],
    "HTTP_ACCEPT" => headers["HTTP_ACCEPT"] || (requested_format == "json" ? "application/json" : nil),
    "CONTENT_LENGTH" => body_string.bytesize.to_s
  }.compact

  headers.each do |k, v|
    env["HTTP_#{k.to_s.upcase.tr('-', '_')}"] = v unless k.to_s.start_with?("HTTP_")
  end

  status = 200
  response_headers = { "Content-Type" => "text/plain" }
  response_body = ""

  begin
    if defined?(::Rails) && ::Rails.application && ::Rails.application.routes.routes.any?
      status, response_headers, body_obj = ::Rails.application.call(env)
      response_body = body_obj.respond_to?(:body) ? body_obj.body : body_obj.join
    else
      # No Rails app mounted; behave like a very small echo server.
      if (env["HTTP_ACCEPT"] || "").to_s.include?("json") ||
         (env["CONTENT_TYPE"] || "").to_s.include?("json") ||
         requested_format == "json"
        response_headers["Content-Type"] = "application/json"
        response_body = params.is_a?(String) ? params : params.to_json
      else
        response_headers["Content-Type"] = "text/plain"
        response_body = params.to_s
      end
    end
  ensure
    if defined?(ActiveRecord::Base) && ActiveRecord::Base.respond_to?(:connection_handler)
      ActiveRecord::Base.connection_handler.clear_active_connections!
    end
  end

  res = ResponseStruct.new(status, response_body, response_headers)
  execution_context[:last_response] = res
  res
end

#put(path, params: {}, headers: {}) ⇒ Object



139
140
141
# File 'lib/crspec/rails/request_helpers.rb', line 139

def put(path, params: {}, headers: {})
  process_request(:put, path, params, headers)
end

#responseObject



41
42
43
# File 'lib/crspec/rails/request_helpers.rb', line 41

def response
  execution_context[:last_response]
end