Reputation: 23
I have some routes that should only exist in the development environment but I can't get the specs for this working. Any ideas what I am doing wrong? I initially tried this in the controller spec but then realised I need :type => :routing to use be_routable so have separated this out. I have debugged and Rails.env has the values I expect in each context. Do I need to reload the routes? Have tried to do this but can't find a syntax that rspec is happy with...
Snippet from routes.rb:
resources :users do
collection do
...
if Rails.env.development?
get :new_development_account
post :create_development_account
end
end
...
Routing spec:
require 'spec_helper'
describe "routes for users controller", :type => :routing do
context "production environment" do
it "development routes do not exist" do
allow(Rails).to receive(:env) { "production".inquiry }
expect(:get => "/ims/users/new_development_account").not_to be_routable
expect(:post => "/ims/users/create_development_account").not_to be_routable
end
end
context "development environment" do
it "development routes exist" do
allow(Rails).to receive(:env) { "development".inquiry }
expect(:get => "/ims/users/new_development_account").to be_routable
expect(:post => "/ims/users/create_development_account").to be_routable
end
end
end
What is particularly odd is that it fails both tests:
Failures:
1) routes for users controller production environment development routes do not exist
Failure/Error: expect(:get => "/ims/users/new_development_account").not_to be_routable
expected {:get=>"/ims/users/new_development_account"} not to be routable, but it routes to {:action=>"show", :controller=>"ims/users", :id=>"new_development_account"}
# /var/code/bundle/ruby/2.2.0/gems/given_core-3.5.4/lib/given/rspec/monkey.rb:31:in `handle_matcher'
# ./spec/routing/users_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
# ./spec/support/database_cleaner.rb:18:in `block (2 levels) in <top (required)>'
2) routes for users controller development environment development routes exist
Failure/Error: expect(:post => "/ims/users/create_development_account").to be_routable
expected {:post=>"/ims/users/create_development_account"} to be routable
# /var/code/bundle/ruby/2.2.0/gems/given_core-3.5.4/lib/given/rspec/monkey.rb:21:in `handle_matcher'
# ./spec/routing/users_controller_spec.rb:18:in `block (3 levels) in <top (required)>'
# ./spec/support/database_cleaner.rb:18:in `block (2 levels) in <top (required)>'
Upvotes: 2
Views: 1261
Reputation: 916
It's been ~4 years already but we've hit this very same setup and ended up with an alternative solution that does not alter the global state [that much] of the app.
As @Vasfed explained:
Routes are loaded once on app start, and Rails.env will be 'test'.
In our case we run tests with rspec_parallel
and had a toggle that would only load ~20% of the routes, and parallel tests would fail at random because the routes suddenly vanished.
Because of this we did Opt 2 (have the routes blocked by a dynamic constraint) for a while until finding out that
Rails.application.routes
is somewhat easy to fabricate [probably at the
expense of CI time].
So, if you attempt something along the lines of:
require 'spec_helper'
describe "routes for users controller", :type => :routing do
context "production environment" do
before { allow(Rails).to receive(:env) { "production".inquiry } }
routes do
ActionDispatch::Routing::RouteSet.new_with_config(Rails.application.config)
end
it "development routes do not exist" do
expect(:get => "/ims/users/new_development_account").not_to be_routable
expect(:post => "/ims/users/create_development_account").not_to be_routable
end
end
context "development environment" do
before { allow(Rails).to receive(:env) { "development".inquiry } }
routes do
ActionDispatch::Routing::RouteSet.new_with_config(Rails.application.config)
end
it "development routes exist" do
expect(:get => "/ims/users/new_development_account").to be_routable
expect(:post => "/ims/users/create_development_account").to be_routable
end
end
end
You'd be able to assert different routes in different envs. Keep in mind though:
#routes
call executes must be as close to the example as possible, it's
called in order of usage. In the example at hand:
#context
#before
#routes
#it
If you move the routes
section outside to the global scope it'll run before
any other block:
#routes
#context
#before
#it
Upvotes: 0
Reputation: 286
The routes can be reloaded with Rails.application.reload_routes!
.
Example:
it "does not have routes in production" do
allow(Rails).to receive(:env) { "production".inquiry }
Rails.application.reload_routes!
expect(:get => "/ims/users/new_development_account").not_to be_routable
expect(:post => "/ims/users/create_development_account").not_to be_routable
end
Upvotes: 2
Reputation: 18444
Routes are loaded once on app start, and Rails.env
will be 'test'.
Usually it's better to keep you development environment as close to production as possible, including routes.
If you want some shortcuts in dev env, there're options:
/ims/users/new
and create
actions with a parameter that will only have effect in development. For example /ims/users/new?development=true
that will also render additional hidden field to pass state to create
I'd go with first option, it's both simple, incapsulates relatively well and most probably your *_development_account
mimic corresponding actions anyway
Upvotes: 0