I’ve used Rack::Test to test Rails and other rack-based frameworks for a long time, but the first time I needed to test the protocol (“http” or “https”) of an app I was stumped.
I wanted to write a test that ensured that non-HTTPS requests were rejected in production, but the request methods in Rack::Test take a path (e.g.
get "/blog") and the protocol/host always defaults to “http://example.org”.
The code being tested looked like this.
class API < Grape::API helpers do def reject_http! error!("The API is only accessible over HTTPS.", 403) if http_request? end def http_request? request.scheme == "http" end def production? ENV["RACK_ENV"] == "production" end end before do reject_http! if production? end get "/" do ... end end
After doing some spelunking in the relevant parts of Rack::Test I discovered that although it doesn’t seem to be explicitly documented anywhere and I’d never seen it done before, Rack::Test actually supports making requests to full URLs, which means you can use it to test the protocol, subdomain, and host of a request!
describe API do before do ENV["RACK_ENV"] = "production" end after do ENV["RACK_ENV"] = "test" end it "allows HTTPS requests in production" do get "https://example.dev" last_response.status.must_equal 200 end it "does not allow HTTP requests in production" do get "http://example.dev" last_response.status.must_equal 403 error = JSON.parse(last_response.body)["error"] error.must_equal "The API is only accessible over HTTPS." end end