I have multiple Rails engines in my Rails 4 beta1 application. I'm installed rspec-rails gem to every engines. And I created my engine following command:
rails plugin new store_frontend --dummy-path=spec/dummy -d postgresql --skip-test-unit --mountable
In my engine's dummy application I configured database and routes. Here is example routes.rb file:
Rails.application.routes.draw do
mount StoreFrontend::Engine => "/store"
end
When I run rspec inside first engine I get following errors:
1) StoreAdmin::DashboardController GET 'index' returns http success
Failure/Error: get 'index'
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"store_admin/dashboard"}
# ./spec/controllers/store_admin/dashboard_controller_spec.rb:8:in `block (3 levels) in <module:StoreAdmin>'
And here is my controller test /It's generated from Rails/:
require 'spec_helper'
module StoreFrontend
describe HomeController do
describe "GET 'index'" do
it "returns http success" do
get 'index'
response.should be_success
end
end
end
end
It seems like controller test is not working. I have model tests and it's working fine. Any idea?
UPDATE 1:
My application structure:
bin/
config/
db/
lib/
log/
public/
tmp/
engine1/
engine2/
engine3/
The solution is very simple. Add use_route to your controller test. Here is the example.
module StoreFrontend
describe HomeController do
describe "GET 'index'" do
it "returns http success" do
get 'index', use_route: 'store_frontend' # in my case
response.should be_success
end
end
end
end
The configuration and spec you show are for StoreFrontend but the error is for StoreAdmin::DashboardController. So it seems like you are just confused about which engine you are testing and/or which engine is failing.
Of course the simple solution is to create the missing route {:action=>"index", :controller=>"store_admin/dashboard"}
In order to get the routing correct when testing Rails engine controllers with Rspec, I typically add the following code to my spec_helper.rb:
RSpec.configure do |config|
config.before(:each, :type => :controller) { #routes = YourEngineName::Engine.routes }
config.before(:each, :type => :routing) { #routes = YourEngineName::Engine.routes }
end
Related
I'm developing a Rails Engine using rails v5.1.0 and rspec-rails 3.5.2.
I have a simple feature spec:
require "rails_helper"
module MyEngineName
RSpec.feature "Some Feature", type: :feature do
it "user can navigate to page and blah blah", :js do
visit edit_job_path(1)
# .... other stuff
end
end
end
This raises the error
undefined method `edit_job_path' for #<RSpec::ExampleGroups::SomeFeature:0x007fc098a570e8>
because the route helper edit_job_path can not be found.
Is there something special I need to do in order to allow my feature specs to access my engine routes?
The RSpec documentation mentions that you can specify the engine routes, but that only appears to be for routing specs. When I added it to the feature specs, it fails with undefined method 'routes'
Thanks!
EDIT: Since my routes file was requested, adding it here. It's pretty short -
# config/routes.rb
MyEngineName::Engine.routes.draw do
root to: redirect("/my_engine_name/jobs")
resources :jobs
end
List of all routes from rake
> rake app:routes
....
....
Routes for MyEngineName::Engine:
root GET / redirect(301, /my_engine_name/jobs)
jobs GET /jobs(.:format) my_engine_name/jobs#index
POST /jobs(.:format) my_engine_name/jobs#create
new_job GET /jobs/new(.:format) my_engine_name/jobs#new
edit_job GET /jobs/:id/edit(.:format) my_engine_name/jobs#edit
job GET /jobs/:id(.:format) my_engine_name/jobs#show
PATCH /jobs/:id(.:format) my_engine_name/jobs#update
PUT /jobs/:id(.:format) my_engine_name/jobs#update
DELETE /jobs/:id(.:format) my_engine_name/jobs#destroy
For API request specs, I tried both ways but it doesn't work
routes { MyEngine::Engine.routes }
and
RSpec.configure do |config|
config.before :each, type: :request do
helper.class.include MyEngine::Engine.routes.url_helpers
end
end
If the above solutions doesn't work, try loading helper urls as rspec configs as below:
RSpec.configure do |config|
config.include MyEngine::Engine.routes.url_helpers
end
Something from this should help. Make sure that you have MyEngineName::Engine.routes, not MyEngineName.routes
require "rails_helper"
module MyEngineName
RSpec.feature "Some Feature", type: :feature do
routes { MyEngineName::Engine.routes }
it "user can navigate to page and blah blah", :js do
# ...
or (another solution)
# place this in `spec/rails_helper.rb` file
RSpec.configure do |config|
config.before :each, type: :feature do
helper.class.include MyEngineName::Engine.routes.url_helpers
end
end
I have a controller spec looking like this:
# config_controller_spec.rb
require "spec_helper"
describe Api::V4::ConfigController, type: :controller do
let(:parsed_response) { response.body.to_json }
describe 'GET app_config' do
it "renders successfully" do
get :app_config
expect(response).to be_success
expect(parsed_response).to eq("{key: val}")
end
end
end
When I run it however, I get:
ActionController::UrlGenerationError:
No route matches {:action=>"app_config", :controller=>"api/v4/config"}
I don't under stand why. I googled around and figured that if I add: use_route: :config to the get call like so: get :app_config, use_route: :config, then it works for some reason, though I don't understand why? But when appending that, I get the following deprecation error:
DEPRECATION WARNING: Passing the `use_route` option in functional tests are deprecated. Support for this option in the `process` method (and the related `get`, `head`, `post`, `patch`, `put` and `delete` helpers) will be removed in the next version without replacement.
Functional tests are essentially unit tests for controllers and they should not require knowledge to how the application's routes are configured. Instead, you should explicitly pass the appropiate params to the `process` method.
Previously the engines guide also contained an incorrect example that recommended using this option to test an engine's controllers within the dummy application.
That recommendation was incorrect and has since been corrected.
Instead, you should override the `#routes` variable in the test case with `Foo::Engine.routes`. See the updated engines guide for details.
Here is my controller:
# config_controller.rb
class Api::V4::ConfigController < Api::V4::BaseController
def app_config
render json: Api::V6::Config.app_config, root: false
end
end
And routes:
# routes.rb
MyApp::Application.routes.draw do
constraints subdomain: /\Awww\b/ do
namespace :api, defaults: {format: 'json'} do
get 'app_config' => 'config#app_config'
end
end
end
Use a request spec instead of a controller spec:
describe "Api V4 Configuration", type: :request do
let(:json) { JSON.parse(response.body) }
subject { response }
describe 'GET app_config' do
before { get "/api/v4/app_config" }
it { should be_successful }
it "has the correct contents" do
expect(json).to include(foo: "bar")
end
end
end
One of biggest changes with Rails 5 was the depreciation of ActionController::TestCase (which RSpec controller specs wrap) in favor of integration tests. Thus using request specs is a more future proof solution - using less abstraction also means that your specs will cover routing properly as well.
Also you don't seem to be nesting your routes properly:
# routes.rb
MyApp::Application.routes.draw do
constraints subdomain: /\Awww\b/ do
namespace :api, defaults: {format: 'json'} do
namespace :v4 do
get 'app_config' => 'config#app_config'
end
end
end
end
See:
Replacing RSpec controller specs
I am trying to update an engine I wrote in rails 4.1 to rails 4.2. This introduced a deprecation warning around using :use_route in my controller specs.
I have removed every place where I am using :use_route and have replaced it with putting routes {MyEngine::Engine.routes} at the top of the controller spec. This has worked as expected for all of the tests in the controller spec except for the ones that deal with shared examples.
None of my shared examples pass and I get the following:
Failure/Error: action
ActionController::UrlGenerationError:
No route matches {:action=>"destroy", :controller=>"foo/roles", :id=>"1"}
I would like to know how to get my shared examples to pass given this way of adding routes to my controller specs.
An example of one of the specs I have is:
spec/controllers/roles_controller_spec.rb
require 'rails_helper'
module Foo
describe RolesController do
routes {Foo::Engine.routes}
before { sign_in_user FactoryGirl.create(:user, admin: true)}
it_behaves_like 'requires admin privilege' do
let(:action) {get :show, id: role.id}
end
end
end
spec/support/shared_examples.rb
shared_examples "requires admin privilege" do
routes { Foo::Engine.routes }
it 'redirects to main app root if user is not an admin' do
session[:user_id] = FactoryGirl.create(:user)
action
expect(response).to redirect_to main_app.root_path
end
end
Any ideas or help is greatly appreciated.
Thanks
I have some controllers that are in subdomains of the controllers folder.
for example, i have a controller in app/controllers/api/v1/offers_controller.rb that looks like this:
class Api::V1::OffersController < ApplicationController
respond_to :json
def index
...some code here
end
end
I tried putting a controller in spec/controllers/api/v1/offers_controller.rb that looks like this:
require 'spec_helper'
descripe Api::V1::OffersController do
describe "GET 'index'" do
it "returns http success" do
get 'index'
response.should be_success
end
end
end
however, when I run rspec spec, this test does not get run at all. I also tried putting it in the spec/controllers directory, named api_v1_offers_controller.rb, and the test is still not run.
How can I write RSpec tests for these types of controllers?
It actually seems it was a mistake it how I named the file. it seems all RSpec tests need to end it _spec
I recently switched started using rspec-rails(2.6.1) with my Rails(3.0.8) app. I'm used to Test::Unit, and I can't seem to get a filter working for my test methods. I like to keep things as DRY as possible, so I'd like to set up a filter that I can call on any test method that will login as an Authlogic user before the test method is called. I tried accomplishing this by using an RSpec filter in spec_helper.rb:
config.before(:each, :login_as_admin => true) do
post "/user_sessions/create", :user_session => {:username => "admin", :password => "admin"}
end
Then I use it in the corresponding test method(in this case spec/controllers/admin_controller_spec.rb):
require 'spec_helper'
describe AdminController do
describe "GET index" do
it("gives a 200 response when visited as an admin", :login_as_admin => true) do
get :index
response.code.should eq("200")
end
end
end
However, I get this error when I run rspec spec:
Failures:
1) AdminController GET index gives a 200 response when visited as an admin
Failure/Error: Unable to find matching line from backtrace
RuntimeError:
#routes is nil: make sure you set it in your test's setup method.
Blech. Can I only send one HTTP request per test? I also tried stubbing out my authenticate_admin method(inside the config.before block), without any luck.
Unfortunately, there is no way at the moment to do what you're trying to do in a globally defined before hook. The reason is that before hooks are executed in the order in which they get registered, and those declared in RSpec.configure are registered before the one that rspec-rails registers internally to set up the controller, request, response, etc.
Also, this has been reported to https://github.com/rspec/rspec-rails/issues/391.
You should use shulda's macrons. To use shoulda modify your spec_helper.rb
RSpec.configure do |config|
config.include Clearance::Shoulda::Helpers
end
And then can setup filter in controller spec like
require 'spec_helper'
describe AdminController do
fixture :users
before(:each) do
sign_in_as users(:your_user)
end
describe "GET index" do
it("gives a 200 response when visited as an admin", :login_as_admin => true) do
get :index
response.code.should eq("200")
end
end
end