Context: an application uses a piece of Rack middleware that must be setup in config.ru, rather than Rails’s internal Middleware chain. This is for reasons not relevant to this question.
Question: how do I make my tests (functional and integration) aware of this middleware?
I’ll ellaborate with an example. Let’s create a pristine Rails 3 app, using rack-rewrite for illustration purposes.
# /config/initializers/example.rb
Rails.application.middleware.insert 0, 'Rack::Rewrite' do
r301 '/so', 'http://stackoverflow.com'
end
# /test/integration/the_test.rb
require 'test_helper'
class TheTest < ActionDispatch::IntegrationTest
test "redirect from /so to http://stackoverflow.com" do
get '/so'
assert_redirected_to 'http://stackoverflow.com'
end
end
If you run the above test, all is good, and with the browser you can confirm that visiting the path /so will redirect you to StackOverflow indeed.
Cool, let’s now set this up outside Rails then. Remove the file /config/initializers/example.rb described above, and change config.ru to the following:
# /config.ru
require ::File.expand_path('../config/environment', __FILE__)
map '/so' do
run Rack::Rewrite do
r301 '', 'http://stackoverflow.com'
end
end
map '/' do
run Deleteme::Application
end
Now, the test will stop working. The functionality does work, as evidenced if you visit /so with your browser. It’s only that the tests are not aware of that Rack setup.
(Thanks Dan Croak for setting me on the right track. This answer completes what he said).
Short answer
Can’t be done for functional tests.
For integration tests, add the following to your test_helper.rb:
Long answer
Functional tests are just unit tests run against controllers. When you say, for example
get :index, you are not resolving a route. Instead, this is a shorthand for calling theindexmethod, with a request environment that includes a mention to the HTTP method being GET.Therefore, it makes sense that your Rack stack does not influence functional tests.
Integration tests are a different matter. You are testing your full stack there, so you will want to test your Rack middlewares too. Only problem is that, by default, these tests only see the middlewares that you add using Rails’s own API.
But I say “by default” because Rails offers a way to change what Rack stack will be tested. By default, integration tests call
Rails.applicationfor their requests. You can change this to anything that suits your needs.By using the code above, we use
Rack::Buildercreate an ad-hoc Rack application. Inside the block, you can put any code that you would normally put inside aconfig.rufile. To avoid code duplication,evalloads ourconfig.rufile. Now our integration tests will load exactly the same application that our app servers expose.