Ruby on Rails - RSpec test for direct route - ruby-on-rails

I have a direct route like so:
direct :homepage do
"http://www.rubyonrails.org"
end
And I am trying to test this but I am not sure how. This is what I have:
describe 'redirect' do
it 'directs to homepage', type: :request do
get :homepage
expect(response).to redirect_to('http://www.rubyonrails.org')
end
end
But this fails:
1) redirect directs to homepage
Failure/Error: get :homepage
URI::InvalidURIError:
bad URI(is not URI?): "http://www.example.com:80homepage"
I have the url_helpers included in my Rspec config.
How do I test a direct route?
See: https://guides.rubyonrails.org/routing.html#direct-routes

As soon as I wrote this example, it became clear.
describe 'redirect' do
it 'directs to homepage' do
expect(homepage_url).to eq('http://www.rubyonrails.org')
end
end
I was writing my test in request specs. This works.

Related

rails/rspec reads render_template method as assert_template 'NoMethodError Exception'

I want to test if my root path renders proper view:
require 'rails_helper'
RSpec.describe "Statics", type: :request do
describe "GET root path" do
it "returns http success" do
get "/"
expect(response).to have_http_status(:success)
end
it 'routes GET / to static#landing_page' do
expect('/').to render_template('static#landing_page')
end
end
end
The second test fails. In order to find out the reasone behind it I type the second command manually with byebug. Then I receive this error message:
*** NoMethodError Exception: assert_template has been extracted to a gem. To continue using it,
add gem 'rails-controller-testing' to your Gemfile.
For some reasone I am not quite sure rspec confuses render_template with assert_template method and fails. How can I fix it to pass this test?
As RSpec docs state:
The render_template matcher is used to specify that a request renders
a given template or layout. It delegates to assert_template
It is available in controller specs (spec/controllers) and request
specs (spec/requests).
NOTE: use redirect_to(:action => 'new') for redirects, not
render_template.
So, no confusion here.

Why am I getting ActionController::UrlGenerationError: "No route matches" in my controller spec?

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

URI::InvalidURIError: bad URI(is not URI?) testing Rails controllers

I get URI::InvalidURIError testing Rails Home controller:
require 'test_helper'
class HomeControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get :index
assert_response :success
end
end
get the following error:
E
Error:
HomeControllerTest#test_should_get_index:
URI::InvalidURIError: bad URI(is not URI?): http://www.example.com:80index
test/controllers/home_controller_test.rb:7:in `block in <class:HomeControllerTest>'
The stack is the following:
Rails 5.0.0.beta3
minitest (5.8.4)
Controller tests inherit from ActionController::TestCase, while your test
inherits from ActionDispatch::IntegrationTest. So you're using an integration test and not a controller test.
The error is:
http://www.example.com:80index
That doesn't look right, does it? ;-)
The solution is to use a full path:
get '/index'
Remember, integration tests aren't really tied to any specific controller (or anything else, for that matter). They test the integration of several components in your application. So if you're testing the index action of a UserController you'd probably need to use /users/index.
If you intended to make a controller test and not an integration test, you want to set the correct superclass. Using get :index (for the index method) should work fine then.
You can try:
get home_index_path
instead of:
get :index

Rspec GET doesn't match route

I'm testing a controller in my application and have the following code in my controller:
describe CsdlController do
describe "GET /csdl/inclusive" do
before do
# Create domains that are included
#domain = create(:validated_domain)
end
it "returns a CSDL with valid domains" do
get "/csdl/include.json"
response.body.should =~ /#{#domain.text}/
end
end
end
I also have the following route:
match "/csdl/:type" => 'csdl#show'
However when I run the specs it gives me the following error:
No route matches {:controller=>"csdl", :action=>"/csdl/include.json"}
I have a feeling that I'm using RSpec incorrectly here but not sure how to solve it. Any ideas?
I should add that it seems to work perfectly when I actually call it through my browser.
In controller tests you call actions via name not via route paths:
get :show, type: 'include', format: 'json'

RSpec Rails Login Filter

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

Resources