Module: RemoteHttpTesting

Defined in:
lib/remote_http_testing.rb,
lib/remote_http_testing/version.rb

Overview

This module helps write integration tests which make HTTP requests to remote servers. Unlike Rack::Test, it doesn’t make requests to an in-process Rack server. Include it into your test case class.

This module’s API should match the API of Rack::Test. In the future, we should consider whether it’s just as easy to amend Rack::Test so that it can make requests to remote servers, since Rack::Test has supoprt for other desirable features.

Constant Summary collapse

VERSION =
"0.1.2"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#headers_for_requestObject

You can set this to be a Hash, and these HTTP headers will be added to all requests.



18
19
20
# File 'lib/remote_http_testing.rb', line 18

def headers_for_request
  @headers_for_request
end

#last_requestObject

Returns the value of attribute last_request.



16
17
18
# File 'lib/remote_http_testing.rb', line 16

def last_request
  @last_request
end

#last_responseObject

Returns the value of attribute last_response.



15
16
17
# File 'lib/remote_http_testing.rb', line 15

def last_response
  @last_response
end

Class Method Details

.populate_uri_with_querystring(uri, query_string_hash) ⇒ Object



103
104
105
106
107
# File 'lib/remote_http_testing.rb', line 103

def self.populate_uri_with_querystring(uri, query_string_hash)
  return if query_string_hash.nil? || query_string_hash == ""
  key_values = query_string_hash.map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
  uri.query = uri.query.to_s.empty? ? key_values : "&" + key_values # uri.query can be nil
end

Instance Method Details

#assert_content_include?(string) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
# File 'lib/remote_http_testing.rb', line 113

def assert_content_include?(string)
  assert_block("Failed: content did not include the string: #{string}") { content_include?(string) }
end

#assert_content_not_include?(string) ⇒ Boolean

Returns:

  • (Boolean)


117
118
119
120
121
# File 'lib/remote_http_testing.rb', line 117

def assert_content_not_include?(string)
  assert_block("Failed: content should not have included this string but it did: #{string}") do
    !content_include?(string)
  end
end

#assert_select(css_selector, options = {}) ⇒ Object

This is intended to provide similar functionality to the Rails assert_select helper. With no additional options, “assert_select(‘my_selector’)” just ensures there’s an element matching the given selector, assuming the response is structured like XML.



131
132
133
134
135
136
# File 'lib/remote_http_testing.rb', line 131

def assert_select(css_selector, options = {})
  raise "You're trying to assert_select when there hasn't been a response yet." unless dom_response
  assert_block("There were no elements matching #{css_selector}") do
    !dom_response.css(css_selector).empty?
  end
end

#assert_status(status_code, helpful_message = last_response.body) ⇒ Object



109
110
111
# File 'lib/remote_http_testing.rb', line 109

def assert_status(status_code, helpful_message = last_response.body)
  assert_equal(status_code.to_i, last_response.code.to_i, helpful_message)
end

#content_include?(string) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
126
# File 'lib/remote_http_testing.rb', line 123

def content_include?(string)
  raise "No request was made yet, or no response was returned" unless last_response
  last_response.body.include?(string)
end

#create_request(url, http_method, params = {}, request_body = nil) ⇒ Object

Used by perform_request. This can be overridden by integration tests to append things to the request, like adding a login cookie.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/remote_http_testing.rb', line 74

def create_request(url, http_method, params = {}, request_body = nil)
  uri = URI.parse(url)
  RemoteHttpTesting::populate_uri_with_querystring(uri, params)
  request_class = case http_method
    when :delete then Net::HTTP::Delete
    when :get then Net::HTTP::Get
    when :post then Net::HTTP::Post
    when :put then Net::HTTP::Put
    when :patch then Net::HTTP::Patch
  end
  request = request_class.new(uri.request_uri)
  request.body = request_body if request_body
  headers_for_request.each { |key, value| request.add_field(key, value) } if headers_for_request
  request
end

#current_serverObject



41
# File 'lib/remote_http_testing.rb', line 41

def current_server() (@temporary_server || self.server) end

#delete(url, params = {}, request_body = nil) ⇒ Object



66
# File 'lib/remote_http_testing.rb', line 66

def delete(url, params = {}, request_body = nil) perform_request(url, :delete, params, request_body) end

#dom_responseObject



23
24
25
# File 'lib/remote_http_testing.rb', line 23

def dom_response
  @dom_response ||= Nokogiri::HTML(last_response.body)
end

#ensure_reachable!(server_url, server_display_name = nil) ⇒ Object

Prints out an error message and exits the program (to avoid running subsequent tests which are just going to fail) if the server is not reachable.



45
46
47
48
49
50
51
# File 'lib/remote_http_testing.rb', line 45

def ensure_reachable!(server_url, server_display_name = nil)
  unless server_reachable?(server_url)
    failure_message = server_display_name ? "#{server_display_name} at #{server_url}" : server_url
    puts "FAIL: Unable to connect to #{failure_message}"
    exit 1
  end
end

#get(url, params = {}, request_body = nil) ⇒ Object



67
# File 'lib/remote_http_testing.rb', line 67

def get(url, params = {}, request_body = nil) perform_request(url, :get, params, request_body) end

#json_responseObject



27
28
29
# File 'lib/remote_http_testing.rb', line 27

def json_response
  @json_response ||= JSON.parse(last_response.body)
end

#patch(url, params = {}, request_body = nil) ⇒ Object



70
# File 'lib/remote_http_testing.rb', line 70

def patch(url, params = {}, request_body = nil) perform_request(url, :patch, params, request_body) end

#perform_request(url, http_method, params = {}, request_body = nil) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/remote_http_testing.rb', line 90

def perform_request(url, http_method, params = {}, request_body = nil)
  self.last_response = @dom_response = @json_response = nil
  url = current_server + url
  uri = URI.parse(url)
  self.last_request = create_request(url, http_method, params, request_body)
  begin
    response = Net::HTTP.new(uri.host, uri.port).request(self.last_request)
  rescue Errno::ECONNREFUSED => error
    raise "Unable to connect to #{self.current_server}"
  end
  self.last_response = response
end

#post(url, params = {}, request_body = nil) ⇒ Object



68
# File 'lib/remote_http_testing.rb', line 68

def post(url, params = {}, request_body = nil) perform_request(url, :post, params, request_body) end

#put(url, params = {}, request_body = nil) ⇒ Object



69
# File 'lib/remote_http_testing.rb', line 69

def put(url, params = {}, request_body = nil) perform_request(url, :put, params, request_body) end

#serverObject

Define this method to return the URL of the HTTP server to talk to, e.g. “localhost:3000



21
# File 'lib/remote_http_testing.rb', line 21

def server() raise "You need to define a server() method." end

#server_reachable?(server_url) ⇒ Boolean

True if the server is reachable. Fails if the server can’t be contacted within 2 seconds.

Returns:

  • (Boolean)


54
55
56
57
58
59
60
61
62
63
64
# File 'lib/remote_http_testing.rb', line 54

def server_reachable?(server_url)
  uri = URI.parse(server_url)
  request = Net::HTTP.new(uri.host, uri.port)
  request.read_timeout = 2
  response = nil
  begin
    response = request.request(create_request(server_url, :get))
  rescue StandardError, Timeout::Error
  end
  !response.nil? && response.code.to_i == 200
end

#use_server(server, &block) ⇒ Object

Temporarily make requests to a different server than the one specified by your server() method.



32
33
34
35
36
37
38
39
# File 'lib/remote_http_testing.rb', line 32

def use_server(server, &block)
  @temporary_server = server
  begin
    yield
  ensure
    @temporary_server = nil
  end
end