I'm having problem with using rspec in ruby-on-rails app
my users_spec.rb
require 'rails_helper'
RSpec.describe 'Get /', type: :request do
it 'test / get method' do
expect(response).to have_http_status(:success)
expect(response).to include('index')
end
end
my routes.rb
Rails.application.routes.draw do
get "/" => "users#index"
end
my users_controller.rb
class UsersController < ApplicationController
def index
end
end
my index.erb
<h1>index</h1>
when I run "bundle exec rspec". , I get error like this
.F
Failures:
1) Get / test / get method
Failure/Error: expect(response).to have_http_status(:success)
expected the response to have a success status code (2xx) but it was
# ./spec/requests/users_spec.rb:5:in `block (2 levels) in <main>'
Finished in 0.11204 seconds (files took 5.18 seconds to load)
2 examples, 1 failure
Failed examples:
rspec ./spec/requests/users_spec.rb:4 # Get / test / get method
and I can't catch where is wrong..
Your spec is not correct. Your spec is not actually calling the endpoint. You need to add a get "/" call, that will actually call the endpoint
require 'rails_helper'
RSpec.describe 'Get /', type: :request do
it 'test / get method' do
get "/" #this is the missing line; this actually makes the request
expect(response).to have_http_status(:success)
expect(response).to include('index')
end
end
Related
I am trying to write an rspec file for my meetings_controller.rb so as to check if the values returned from my database are correct.
When I go to localhost:3000/meeting.json, this is the result of my data from the database
my rspec file is trying to check if the correct values are returned.
I created a folder called controller under specs (after I have installed rspec)and have the file meeting_controller_spec.rb
require 'rails_helper'
# Change this ArticlesController to your project
RSpec.describe MeetingsController, type: :controller do
describe "GET #index" do
# check index
it "returns a success response" do
get :index
puts response.body
expect(response).to have_http_status(:ok)
end
end
end
I tried to print the response body but nothing is returning. Is there a way to do this?
(base) adam-a01:reservation adrianlee$ rspec
.
Finished in 0.0892 seconds (files took 12.15 seconds to load)
1 example, 0 failures
Btw this is my meeting_controller.rb
class MeetingsController < ApplicationController
before_action :set_meeting, only: [:show, :edit, :update, :destroy]
# GET /meetings
# GET /meetings.json
def index
#meetings = Meeting.all
#meeting = Meeting.new
end
end
Update: I also tried this method as suggested below but it didnt work still
# Change this ArticlesController to your project
RSpec.describe MeetingsController, type: :controller do
describe "GET #index" do
# check index
it "returns a success response" do
get :index
raise response.body
expect(response).to have_http_status(:ok)
end
end
end
This is the error raised
Failures:
1) MeetingsController GET #index returns a success response
Failure/Error: raise response.body
RuntimeError:
# ./spec/controllers/meeting_controller_spec.rb:10:in `block (3 levels) in <top (required)>'
If you are trying to get this value for a debugging purpose you should use byebug or pry gems.
If you choose byebug, add it to your gemfile gem 'byebug' on test environment.
run bundle install and after that you are able to use it on your tests
So replace the puts with byebug
describe "GET #index" do
# check index
it "returns a success response" do
get :index
byebug
expect(response).to have_http_status(:ok)
end
end
At the console now you are exactly there. Just type response.body and enter to print it's value.
When you are done, just type c and then enter to release the console e continue your tests.
Also check here for more information about debugging with byebug
In my case I do it like this:
require 'rails_helper'
describe SuppliersController, type: :controller do
describe 'GET /suppliers' do
let!(:access_token) { create :access_token }
let!(:admin_user_token) do
create :user_token, resource_owner: create(:admin_user)
end
context 'when the requester is an admin' do
it 'returns HTTP status 200 (OK)' do
allow(controller).to receive(:doorkeeper_token) { access_token }
#request.env['HTTP_X_USERTOKEN'] = admin_user_token.token
get :index
raise response.body.inspect ## Here is what prints the value in the console.
body = JSON.parse response.body
expect(response).to have_http_status :ok
expect(body['status']).to eq 'OK'
end
end
end
end
To run the test:
rspec spec/controllers/suppliers/suppliers_controller_index_spec.rb
And it gives me the output:
F
Failures:
1) SuppliersController GET /suppliers when the requester is an admin returns HTTP status 200 (OK)
Failure/Error: raise response.body.inspect
RuntimeError:
"{\"status\":\"OK\",\"message\":\"Your request has been processed successfully.\",\"data\":[],\"page\":{\"current_page\":1,\"prev_page\":null,\"next_page\":null,\"per_page\":25,\"total_pages\":0}}"
# ./spec/controllers/suppliers/suppliers_controller_index_spec.rb:17:in `block (4 levels) in <top (required)>'
Finished in 0.47594 seconds (files took 2.82 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/controllers/suppliers/suppliers_controller_index_spec.rb:11 # SuppliersController GET /suppliers when the requester is an admin returns HTTP status 200 (OK)
I have to say raise a runtime error to check variable value is not a good practice,maybe you should try gem 'pry' or gem 'byebug' suggested by #DR7.
Another thing you need make sure is did you run rails s and rspec in different environment?This maybe lead to they connect to separate db.
I am doing some simple integration testing. I want to test the sold_items action in the users controller. I have confirmed that the route exists and returns json by accessing it from the browser. However, rspec is telling me that the route doesn't exist. PLease see below, the spec, the error, and my route.rb. Thanks!
spec:
require 'rails_helper'
RSpec.describe UsersController, type: :controller do
describe "GET #items" do
it "returns http success" do
user = FactoryGirl.create(:user)
get "users/#{user.id}/sold_items"
expect(response).to have_http_status(:success)
end
end
end
fail message:
1) UsersController GET #items returns http success
Failure/Error: get "users/#{user.id}/sold_items"
ActionController::UrlGenerationError:
No route matches {:action=>"users/10/sold_items", :controller=>"users"}
# ./spec/controllers/users_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
routes.rb
Rails.application.routes.draw do
resources :users
resources :items
get "users/:id/sold_items" => "users#sold_items"
EDIT
spec
require 'rails_helper'
RSpec.describe UsersController, type: :controller do
describe "GET #items" do
it "returns http success" do
user = FactoryGirl.create(:user)
get "users/:id/sold_items", id: user.id
expect(response).to have_http_status(:success)
end
end
end
failure message
2) UsersController GET #items returns http success
Failure/Error: get "users/:id/sold_items", id: user.id
ActionController::UrlGenerationError:
No route matches {:action=>"users/:id/sold_items", :controller=>"users", :id=>"12"}
# ./spec/controllers/users_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
EDIT.2 MarvC second suggestion
require 'rails_helper'
RSpec.describe UsersController, type: [:request, :controller] do
describe "GET #items" do
it "returns http success" do
user = FactoryGirl.create(:user)
get "/users/:id/sold_items", id: user.id
expect(response).to have_http_status(:success)
end
end
end
failure
looks like the user.id isn't being passed in properly here
2) UsersController GET #items returns http success
Failure/Error: #sold_items = User.find(params[:id]).seller_items.sold
ActiveRecord::RecordNotFound:
Couldn't find User with 'id'=:id
# ./app/controllers/users_controller.rb:6:in `sold_items'
# ./spec/controllers/users_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
One Solution:
when I use string interpolation to pass user.id into the url it works...
require 'rails_helper'
RSpec.describe UsersController, type: [:request, :controller] do
describe "GET #items" do
it "returns http success" do
user = FactoryGirl.create(:user)
get "users/#{user.id}/sold_items", id: user.id
expect(response).to have_http_status(:success)
end
end
end
It seems your syntax is wrong.
change:
get "users/#{user.id}/sold_items"
To:
rails 4
get "users/:id/sold_items", id: user.id
rails 5
get "users/:id/sold_items", params: { id: user.id }
I use this tests for FacultiesController:
describe FacultiesController do
describe "GET show" do
it "responds successfully with an HTTP 200 status code" do
get :show
expect(response).to be_success
expect(response).to have_http_status(200)
end
end
describe "GET index" do
it "responds successfully with an HTTP 200 status code" do
get :index
expect(response).to be_success
expect(response).to have_http_status(200)
end
end
end
Output:
Failures:
1) FacultiesController GET show responds successfully with an HTTP 200 status code
Failure/Error: get :show
ActionController::UrlGenerationError:
No route matches {:action=>"show", :controller=>"faculties"}
# ./spec/controllers/faculties_controller_spec.rb:5:in `block (3 levels) in <top (required)>'
2) FacultiesController GET index responds successfully with an HTTP 200 status code
Failure/Error: #faculties=Faculty.where(:university_id => #university.id).all
NoMethodError:
undefined method `id' for nil:NilClass
# ./app/controllers/faculties_controller.rb:5:in `index'
# ./spec/controllers/faculties_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
1) When I run rake routes I see
faculty GET /faculties/:shortcut(.:format) faculties#show
So, I suppose I need to specify shortcut with this GET. But how?
I tried add :shortcut=>"test", but this didn't work, also tried params: {:shortcut=>"test"}. Nothing works until I just write "GET faculties/test" and also remove line get :show.
Is that as it should to be?
2)
Failure/Error: #faculties=Faculty.where(:university_id => #university.id).all
NoMethodError:
undefined method `id' for nil:NilClass
First of all, it, again, work just fine in browser testing. I use module which helps controller to define #university by subdomain.
How can I pass this to test? Should I just provide some option to get index? By the way, it is all defined in my factories.rb file, as subdomain string is stored in db.
I though may be I should invoke factories new instance in this spec before describe?
university = create(:university)
faculty = create(:faculty)
Thanks in advance.
1) You should create a new faculty and pass it's id
describe "GET show" do
let(:faculty) {FactoryGirl.create(:faculty)}
it "responds successfully with an HTTP 200 status code" do
get :show, :id => faculty.id #or get :show, :shortcut => faculty.id
expect(response).to be_success
expect(response).to have_http_status(200)
end
end
2) You should create faculty & university & pass it as params
describe "GET index" do
let(:university) {FactoryGirl.create(:university)}
before(:each) do
FactoryGirl.create(:faculty, :university_id => university.id)
end
it "responds successfully with an HTTP 200 status code" do
get :index, university_id => university.id
expect(response).to be_success
expect(response).to have_http_status(200)
end
end
Please provide index route if it wouldn't work
hello i'm doing some test of my application with Rspec (this is my very first time i'm using it)
this is my test file located in spec/controllers/recipes_controller_spec.rb:
require 'spec_helper'
describe RecipesController do
render_views
describe "index" do
before do
Recipe.create!(name: 'Baked Potato w/ Cheese')
Recipe.create!(name: 'Garlic Mashed Potatoes')
Recipe.create!(name: 'Potatoes Au Gratin')
Recipe.create!(name: 'Baked Brussel Sprouts')
xhr :get, :index, format: :json, keywords: keywords
end
subject(:results) { JSON.parse(response.body) }
def extract_name
->(object) { object["name"] }
end
context "when the search finds results" do
let(:keywords) { 'baked' }
it 'should 200' do
expect(response.status).to eq(200)
end
it 'should return two results' do
expect(results.size).to eq(2)
end
it "should include 'Baked Potato w/ Cheese'" do
expect(results.map(&extract_name)).to include('Baked Potato w/ Cheese')
end
it "should include 'Baked Brussel Sprouts'" do
expect(results.map(&extract_name)).to include('Baked Brussel Sprouts')
end
end
context "when the search doesn't find results" do
let(:keywords) { 'foo' }
it 'should return no results' do
expect(results.size).to eq(0)
end
end
end
end
when i try to execute it by the command:
bundle exec rspec spec/controllers/recipes_controller_spec.rb
i fail all my tests with this error:
Failure/Error: xhr :get, :index, format: :json, keywords: keywords
NameError:
uninitialized constant RecipesController::Recipes
# ./app/controllers/recipes_controller.rb:4:in `index'
# ./spec/controllers/recipes_controller_spec.rb:12:in `block (3 levels) in <top (required)>'
i've tried to look all my code but i haven't find out the error
NameError: uninitialized constant RecipesController::Recipes
means you used Recipes instead of Recipe somewhere (line 4 in index) in controller, and since your model is called Recipe (singular), you're getting NameError exception.
What am I forgetting?
routes:
get "/comingsoon" => "visitors#comingsoon"
resources :visitors
controller:
class VisitorsController < ApplicationController
def comingsoon
#new_visitor = Visitor.new
end
end
spec:
require 'spec_helper'
describe VisitorsController do
describe "GET /comingsoon" do
it "should be happy" do
get "/comingsoon"
response.should be_success
end
end
end
And here's the result:
✗ rspec spec/controllers/visitors_controller_spec.rb
F
Failures:
1) VisitorsController GET /comingsoon should be valid
Failure/Error: get "/comingsoon"
ActionController::RoutingError:
No route matches {:controller=>"visitors", :action=>"/comingsoon"}
# ./spec/controllers/visitors_controller_spec.rb:7:in `block (3 levels) in <top (required)>'
Finished in 0.14226 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/controllers/visitors_controller_spec.rb:6 # VisitorsController GET /comingsoon should be valid
What am I forgetting?
In your spec file replace get "/comingsoon"
with get "comingsoon"
When you spec a controller with rspec the operand of the http verb (get, post, put, delete) is an action of the controller rather than a url.
Possibly daft suggestion, but you have a view right? Otherwise you have to tell your controller to render something.