RSpec Post and Namespaces - ruby-on-rails

I first used this RSpec test to post to my Env controller. After changing the namespace of my controller I can't seem to appropriately post to this controller. The namespace is 'api', and I've tried moving the RSpec file into an 'api' folder, tried changing the actual post parameters themselves, and added 'Api::' to the describe block. Any thoughts?
require 'spec_helper'
describe Api::EnvsController do
describe "POST create" do
it "creates a new env" do
expect { post :create, :env => {:name => "mym"} }.to change(Env,:count).by(1)
end
end
end

Related

Rails engine: rake routes show its routes but on rspec execution "No route matches" is thrown

I'm trying to test a controller that is inside an engine my application is using. The spec is not within the engine, but in the application itself (I tried to test within the engine but also had problems).
My engine has the following routes.rb:
Revision::Engine.routes.draw do
resources :steps, only: [] do
collection { get :first }
end
end
The engine is mounted on the application routes.rb normally:
mount Revision::Engine => "revision"
When I run rake routes, at the last lines I get:
Routes for Revision::Engine:
first_steps GET /steps/first(.:format) revision/steps#first
root / revision/steps#first
On my engine's controller (lib/revision/app/controllers/revision/steps_controller.rb), I have:
module Revision
class StepsController < ApplicationController
def first
end
end
end
On Rspec, I test this controller with:
require 'spec_helper'
describe Revision::StepsController do
it "should work" do
get :first
response.should be_success
end
end
Then when I run this spec, I get:
ActionController::RoutingError:
No route matches {:controller=>"revision/steps", :action=>"first"}
To be sure that the route doesn't really exist, I added this to the spec:
before do
puts #routes.set.to_a.map(&:defaults)
end
And the result is this:
[...]
{:action=>"show", :controller=>"devise/unlocks"}
{:action=>"revision"}
It has only the :action parameter.
What may be wrong?
When you're trying to test an engine's controllers, you need to specify what route set you want the controller test to use, otherwise it will run it against the main app's. To do that, pass use_route: :engine_name to the get method.
require 'spec_helper'
describe Revision::StepsController do
it "should work" do
get :first, use_route: :revision # <- this is how you do it
response.should be_success
end
end

rspec - customised route

I have simplified an issue I am having to the following
I have a route that looks like this
namespace :client do
resources :thing, :only => [:index]
end
and the simple rspec test
describe Client::ThingController do
describe "GET 'index'" do
it "returns http success" do
get 'index'
response.should be_success
end
end
end
However what I'd like to do is alter the url I use to access the resource from
/client/thing.json
to
/api/client/v1/thing.json
1) How do I update my routes and rspec?
If I then wanted to parameterise the uri such that I could extract the api_version
/api/client/[api_version]/thing.json
2) How would this effect my routes and simple rspec test?
I'd previously tried what #Mori had suggested before I had posted but without having the multiple routes as proposed, I should have mentioned that in the original post.
What I eventually got that worked is:
1) In routes.rb I added
match "api/client/:api_version/thing" => 'client/thing#index'
NOTE: The missing leading '/' ie match "/api/... => match "api/... it seems to make all the difference to rspec.
2) And in my rspec thing_controller_spec.rb I now have this
describe Client::ThingController do
describe "GET 'index'" do
it "returns http success" do
get 'index', :api_version => 'v1'
response.should be_success
end
end
end
I was close before but it was the leading '/' in routes.rb that broke me even though I could navigate to the url in a browser.

rspec-rails: Failure/Error: get "/" No route matches

Trying out rspec-rails. I get a weird error - no routes are supposedly found, even though I can access them fine in the browser when running rails s.
I even tried it with just /
Failure/Error: get "/"
ActionController::RoutingError:
No route matches {:controller=>"action_view/test_case/test", :action=>"/"}
I can definitely access / and other resources in the browser, though. Is there something I could've missed when setting rspec up? I put it into the Gemfile and ran rspec:install.
Thank you,
MrB
edit: Here's my test
1 require 'spec_helper'
2
3 describe "resource" do
4 describe "GET" do
5 it "contains /" do
6 get "/"
7 response.should have_selector("h1", :content => "Project")
8 end
9 end
10 end
Here's my route file:
myApp::Application.routes.draw do
resources :groups do
resources :projects
end
resources :projects do
resources :variants
resources :steps
member do
get 'compare'
end
end
resources :steps do
resources :costs
end
resources :variants do
resources :costs
end
resources :costs
root :to => "home#index"
end
My spec_helper.rb:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.mock_with :rspec
config.include RSpec::Rails::ControllerExampleGroup
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
end
Didn't really change anything here, I think.
As far as i know, you are trying to combine two tests into one. In rspec this should be solved in two steps. In one spec you test the routing, and in another you test the controller.
So, add a file spec/routing/root_routing_spec.rb
require "spec_helper"
describe "routes for Widgets" do
it "routes /widgets to the widgets controller" do
{ :get => "/" }.should route_to(:controller => "home", :action => "index")
end
end
And then add a file spec/controllers/home_controller_spec.rb, and I am using the extended matchers defined by shoulda or remarkable.
require 'spec_helper'
describe HomeController do
render_views
context "GET index" do
before(:each) do
get :index
end
it {should respond_with :success }
it {should render_template(:index) }
it "has the right title" do
response.should have_selector("h1", :content => "Project")
end
end
end
Actually, I almost never use render_views but always test my components as isolated as possible. Whether the view contains the correct title I test in my view-spec.
Using rspec i test each component (model, controller, views, routing) separately, and i use cucumber to write high level tests to slice through all layers.
Hope this helps.
You have to describe a controller for a controller test. Also, since you're testing the contents of the view in the controller test and not a separate view spec, you have to render_views.
describe SomeController, "GET /" do
render_views
it "does whatever" do
get '/'
response.should have_selector(...)
end
end

Why doesn't this Rails Rspec Test Work?

I create all the routes of my program manually and so do with my rspec tests of course. Generally, my routes and tests work fine, but i have a problem with the test for my characters controller. The route is :
scope :path => '/characters', :controller => :characters do
get '/' => :show, :as => 'user_character'
end
The /characters works fine when tested with my browser. Everything seems fine. But, the test :
require 'spec_helper'
require 'devise/test_helpers'
describe CharactersController do
login_user
describe "when it GETS 'show'" do
it "should render the template and be successful" do
get :show
response.should render_template(:show)
response.should be_success
end
end
end
Fails with the error :
1) CharactersController when it GETS 'show' should render the template and be successful
Failure/Error: get :show
ActionController::RoutingError:
No route matches {:controller=>"characters", :action=>"show"}
# ./spec/controllers/characters_controller_spec.rb:9
All my controllers have similar tests that work fine. Why does this not work ?
IMPORTANT EDIT :
Just saw that if i turn Spork off, the test passes ! Why is this happening ? Does Spork need to be restarted every time a new test is added ?
You have to restart spork when changing routes.
Or put this in your spec_helper.rb:
Spork.each_run do
ApplicationName::Application.reload_routes!
end
See also "Speedy Test Iterations for Rails 3 with Spork and Guard"

Testing an RSpec controller action that can't be accessed directly

I've got a controller that can't be accessed directly, in the traditional RESTful way, but rather only through a particular url.
Normally I'm used to using get and post in my controller specs to call controller actions. Is there a way that I can exercise my controller by visiting a particular url?
EDIT:
Here is my route:
Larzworld::Application.routes.draw do
match '/auth/:provider/callback' => 'authentications#create'
devise_for :users, :controllers => {:registrations => "registrations"}
root :to => 'pages#home'
end
Here is my spec:
require 'spec_helper'
describe AuthenticationsController do
before(:each) do
request.env["omniauth.auth"] = {"provider" => "twitter", "uid" => "12345678"}
end
describe 'POST create' do
it "should find the Authentication using the uid and provider from omniauth" do
Authentication.should_receive(:find_by_provider_and_uid)
post 'auth/twitter/callback'
end
end
end
and here is the error I receive:
Failures:
1) AuthenticationsController POST create should find the Authentication using the uid and provider from omniauth
Failure/Error: post 'auth/twitter/callback'
No route matches {:action=>"auth/twitter/callback", :controller=>"authentications"}
# ./spec/controllers/authentications_controller_spec.rb:13
Finished in 0.04878 seconds
1 example, 1 failure
Controller tests use the four HTTP verbs (GET, POST, PUT, DELETE), regardless of whether your controller is RESTful. So if you have a non-RESTful route (Rails3):
match 'example' => 'story#example'
the these two tests:
require 'spec_helper'
describe StoryController do
describe "GET 'example'" do
it "should be successful" do
get :example
response.should be_success
end
end
describe "POST 'example'" do
it "should be successful" do
post :example
response.should be_success
end
end
end
will both pass, since the route accepts any verb.
EDIT
I think you're mixing up controller tests and route tests. In the controller test you want to check that the logic for the action works correctly. In the route test you check that the URL goes to the right controller/action, and that the params hash is generated correctly.
So to test your controller action, simply do:
post :create, :provider => "twitter"`
To test the route, use params_from (for Rspec 1) or route_to (for Rspec 2):
describe "routing" do
it "routes /auth/:provider/callback" do
{ :post => "/auth/twitter/callback" }.should route_to(
:controller => "authentications",
:action => "create",
:provider => "twitter")
end
end

Resources