I'm using Rails 4.2 rspec 3.5
after basic scaffold generation, i was trying to run rspec, but constantly getting this errors.
controller test
it "updates the requested" do
some_object = SomeObject.create! valid_attributes
put :update, params: {id: some_object.to_param, some_object: new_attributes}, session: valid_session
some_object.reload
skip("Add assertions for updated state")
end
gives this output
Failure/Error: put :update, params: {id: some_object.to_param, some_object: valid_attributes}, session: valid_session
ActionController::UrlGenerationError:
No route matches {:action=>"update"
And views test
require 'rails_helper'
RSpec.describe "some_objects/edit", type: :view do
before(:each) do
#some_object = assign(:some_object, SomeObject.create!(
:first_name => "MyString",
:last_name => "MyString"
))
end
it "renders the edit some_object form" do
render
assert_select "form[action=?][method=?]", some_object_path(#some_object), "post" do
assert_select "input#some_object_first_name[name=?]", "some_object[first_name]"
assert_select "input#some_object_last_name[name=?]", "some_object[last_name]"
end
end
end
gives this output:
Failure/Error: <%= form_for(#some_object) do |f| %>
ActionView::Template::Error:
undefined method `polymorphic_path' for #<#<Class:0x005606c04fff98>:0x005606c04ffb60>
This is generated code. I have changed only valid_attributes hash, and this seem to be some bug in rails/rspec. Do you have any solution
Problem is in passing params for :update. Simply remove params: and it will work:
it "updates the requested" do
some_object = SomeObject.create! valid_attributes
put :update, {id: some_object.to_param, some_object: new_attributes}, session: valid_session
some_object.reload
skip("Add assertions for updated state")
end
Related
Here is my rspec test code
require 'rails_helper'
RSpec.describe Users::PaymentController, type: :controller do
let(:user) { create(:user) }
let(:secure_user) { create(:secure_user, user_id: user.id, email: 'abc123#mail.com', birth_date: '1990-01-01', gender: 'female', nation: 'jp', prefecture: 'Tokyo-to', municipality: 'Shibuya-ku') }
describe 'POST #create' do
params = {
birth_date: '2000-01-01',
gender: 'male',
prefecture: 'Osaka-fu',
municipality: 'Osaka-shi'
}
it "changes secure_user's attributes" do
expect do
post :create, params: params
end.to change{ secure_user.birth_date }.from('1990-01-01').to('2000-01-01')
end
end
end
and here is the related part from Users::PaymentController
module Users
class PaymentController < Users::BaseController
def create
current_user.secure_user.update(user_personal_info_params)
......
......
end
private
def user_personal_info_params
params.permit(:birth_date, :gender, :nation, :prefecture, :municipality)
end
end
end
The logic is: add new info to current_user.secure_user while payment is created.
But the test fails and I don't know the reason.
1) Users::PaymentController POST #create changes secure_user's attributes
Failure/Error:
expect do
post :create, params: user_info
binding.pry
end.to change{ secure_user.birth_date }.from('1990-01-01').to('2000-01-01')
expected `secure_user.birth_date` to have changed from "1990-01-01" to "2000-01-01", but did not change
I am not very familiar with RSpec (and so does English), much appreciated if anybody could help me solve this problem.
Try to use .reload
...
end.to change{ secure_user.reload.birth_date }.from('1990-01-01').to('2000-01-01')
The object doesn't get updated inside the test, you have to reload it, to have the up to date attributes.
I have some errors while testing with RSpec. This is my code:
\spec\views\post_categories\edit.html.haml_spec.rb
require 'rails_helper'
RSpec.describe "post_categories/edit", type: :view do
before do
login_user
#post_category = FactoryBot.create(:post_category)
end
it "renders the edit post_category form" do
render
assert_select "form[method=?]", "post" do
assert_select "input[name=?]", "post_category[title]"
assert_select "textarea[name=?]", "post_category[description]"
end
end
end
After it I get such an error:
post_categories/edit renders the edit post_category form
Failure/Error: = simple_form_for(#post_category) do |f|
ActionView::Template::Error:
No route matches {:action=>"show", :controller=>"post_categories", :locale=>#<PostCategory id: 1, title:
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", description:
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", reated_at:
"2021-11-15 11:04:50.292970000 +0000", updated_at: "2021-11-15
11:04:50.292970000 +0000">}, missing required keys: [:id]
Did you mean? post_category_url
admin_post_category_url
The #post_category exsist and corrrect, but simple_form doesn't work on test
Why #post_category got in :locale and how it repair?
I changed all link_to <subject> to link_to <subject>_path(id: subject.id)
Why it needed for rspec I don't know
I have a rails app with a cars model that takes the attribute of 'model'. I'm just trying to run a test to see if the index method in the cars controller will display all the cars.
I'm not sure how to go about this. The test currently passes, but it shouldn't as I currently have an empty index method. How could I test this and what do I need to add. I've tried to read documentation with no luck. thanks
require 'rails_helper'
RSpec.describe CarsController, type: :controller do
context "test" do
it "displays all cars" do
get :index
end
end
end
with the current test file you have posted, your test should pass because you are doing a request to the index action and as long as there is an index action the test will pass.
require 'rails_helper'
RSpec.describe CarsController, type: :controller do
context "test" do
it "displays all cars" do
get :index
end
end
end
However I see some people have recommended to use assigns, when using assigns to test you will need to assigns all the cars to an instance variable e.g. #cars = Cars.all or whatever records you need and also you should have your test data setup properly.
In your test you should also have some sort of list of cars to test against, e.g assuming you are using FactoryGirl/Bot:
let(:cars) { create_list :car, 3 }
You test file should than look something like this:
require 'rails_helper'
RSpec.describe CarsController, type: :controller do
let(:cars) { create_list :car, 3 }
context "test" do
it "displays all cars" do
get :index
expect(assigns(:cars)).to eq cars
end
end
end
Hope my answer helps.
You're looking to use assigns in your controller specs. Since you don't seem to have any code yet, the fastest way to show you an example is to just run rails g scaffold car. Assuming you have rspec-rails in your Gemfile, you should get something like this in spec/controllers/cars_controller_spec.rb:
require 'rails_helper'
# This spec was generated by rspec-rails when you ran the scaffold generator.
# It demonstrates how one might use RSpec to specify the controller code that
# was generated by Rails when you ran the scaffold generator.
#
# It assumes that the implementation code is generated by the rails scaffold
# generator. If you are using any extension libraries to generate different
# controller code, this generated spec may or may not pass.
#
# It only uses APIs available in rails and/or rspec-rails. There are a number
# of tools you can use to make these specs even more expressive, but we're
# sticking to rails and rspec-rails APIs to keep things simple and stable.
#
# Compared to earlier versions of this generator, there is very limited use of
# stubs and message expectations in this spec. Stubs are only used when there
# is no simpler way to get a handle on the object needed for the example.
# Message expectations are only used when there is no simpler way to specify
# that an instance is receiving a specific message.
RSpec.describe CarsController, type: :controller do
# This should return the minimal set of attributes required to create a valid
# Car. As you add validations to Car, be sure to
# adjust the attributes here as well.
let(:valid_attributes) {
skip("Add a hash of attributes valid for your model")
}
let(:invalid_attributes) {
skip("Add a hash of attributes invalid for your model")
}
# This should return the minimal set of values that should be in the session
# in order to pass any filters (e.g. authentication) defined in
# CarsController. Be sure to keep this updated too.
let(:valid_session) { {} }
describe "GET #index" do
it "assigns all cars as #cars" do
car = Car.create! valid_attributes
get :index, params: {}, session: valid_session
expect(assigns(:cars)).to eq([car])
end
end
describe "GET #show" do
it "assigns the requested car as #car" do
car = Car.create! valid_attributes
get :show, params: {id: car.to_param}, session: valid_session
expect(assigns(:car)).to eq(car)
end
end
describe "GET #new" do
it "assigns a new car as #car" do
get :new, params: {}, session: valid_session
expect(assigns(:car)).to be_a_new(Car)
end
end
describe "GET #edit" do
it "assigns the requested car as #car" do
car = Car.create! valid_attributes
get :edit, params: {id: car.to_param}, session: valid_session
expect(assigns(:car)).to eq(car)
end
end
describe "POST #create" do
context "with valid params" do
it "creates a new Car" do
expect {
post :create, params: {car: valid_attributes}, session: valid_session
}.to change(Car, :count).by(1)
end
it "assigns a newly created car as #car" do
post :create, params: {car: valid_attributes}, session: valid_session
expect(assigns(:car)).to be_a(Car)
expect(assigns(:car)).to be_persisted
end
it "redirects to the created car" do
post :create, params: {car: valid_attributes}, session: valid_session
expect(response).to redirect_to(Car.last)
end
end
context "with invalid params" do
it "assigns a newly created but unsaved car as #car" do
post :create, params: {car: invalid_attributes}, session: valid_session
expect(assigns(:car)).to be_a_new(Car)
end
it "re-renders the 'new' template" do
post :create, params: {car: invalid_attributes}, session: valid_session
expect(response).to render_template("new")
end
end
end
describe "PUT #update" do
context "with valid params" do
let(:new_attributes) {
skip("Add a hash of attributes valid for your model")
}
it "updates the requested car" do
car = Car.create! valid_attributes
put :update, params: {id: car.to_param, car: new_attributes}, session: valid_session
car.reload
skip("Add assertions for updated state")
end
it "assigns the requested car as #car" do
car = Car.create! valid_attributes
put :update, params: {id: car.to_param, car: valid_attributes}, session: valid_session
expect(assigns(:car)).to eq(car)
end
it "redirects to the car" do
car = Car.create! valid_attributes
put :update, params: {id: car.to_param, car: valid_attributes}, session: valid_session
expect(response).to redirect_to(car)
end
end
context "with invalid params" do
it "assigns the car as #car" do
car = Car.create! valid_attributes
put :update, params: {id: car.to_param, car: invalid_attributes}, session: valid_session
expect(assigns(:car)).to eq(car)
end
it "re-renders the 'edit' template" do
car = Car.create! valid_attributes
put :update, params: {id: car.to_param, car: invalid_attributes}, session: valid_session
expect(response).to render_template("edit")
end
end
end
describe "DELETE #destroy" do
it "destroys the requested car" do
car = Car.create! valid_attributes
expect {
delete :destroy, params: {id: car.to_param}, session: valid_session
}.to change(Car, :count).by(-1)
end
it "redirects to the cars list" do
car = Car.create! valid_attributes
delete :destroy, params: {id: car.to_param}, session: valid_session
expect(response).to redirect_to(cars_url)
end
end
end
I've read through every similar question I could find and still can't figure out my problem.
# routes.rb
Rails.application.routes.draw do
resources :lists, only: [:index, :show, :create, :update, :destroy] do
resources :items, except: [:new]
end
end
# items_controller.rb (excerpt)
class ItemsController < ApplicationController
...
def create
#list = List.find(params[:list_id])
...
end
...
end
# items_controller_spec.rb (excerpt)
RSpec.describe ItemsController, type: :controller do
...
let!(:list) { List.create(title: "New List title") }
let(:valid_item_attributes) {
{ title: "Some Item Title", complete: false, list_id: list.id }
}
let!(:item) { list.items.create(valid_item_attributes) }
describe "POST #create" do
context "with valid params" do
it "creates a new item" do
expect {
post :create, { item: valid_item_attributes, format: :json }
}.to change(Item, :count).by(1)
end
end
end
...
end
And the RSpec error:
1) ItemsController POST #create with valid params creates a new item
Failure/Error: post :create, { item: valid_item_attributes, format: :json }
ActionController::UrlGenerationError:
No route matches {:action=>"create", :controller=>"items", :format=>:json, :item=>{:title=>"Some Item Title", :complete=>false, :list_id=>1}}
The output from rake routes:
list_items GET /lists/:list_id/items(.:format) items#index
POST /lists/:list_id/items(.:format) items#create
edit_list_item GET /lists/:list_id/items/:id/edit(.:format) items#edit
list_item GET /lists/:list_id/items/:id(.:format) items#show
PATCH /lists/:list_id/items/:id(.:format) items#update
PUT /lists/:list_id/items/:id(.:format) items#update
DELETE /lists/:list_id/items/:id(.:format) items#destroy
I can successfully create a new item in an existing list via curl which tells me that the route is ok, I must be doing something wrong in my test.
curl -i -X POST -H "Content-Type:application/json" -H "X-User-Email:admin#example.com" -H "X-Auth-xxx" -d '{ "item": { "title": "new item", "complete": "false"} }' http://localhost:3000/lists/5/items
I am really confused. My routes are setup correctly. A ItemsController#create method definitely exists. The rest of the tests in items_controller_spec.rb pass without issue.
Am I missing something obvious?
Here are the fixes I had to make to my tests (items_controller_spec.rb). I was not passing the correct hash to post create:.
describe "POST #create" do
context "with valid params" do
it "creates a new item" do
expect {
post :create, { list_id: list.id, item: valid_item_attributes, format: :json }
}.to change(Item, :count).by(1)
end
it "assigns a newly created item as #item" do
post :create, { list_id: list.id, item: valid_item_attributes, format: :json }
expect(assigns(:item)).to be_a(Item)
expect(assigns(:item)).to be_persisted
end
end # "with valid params"
context "with invalid params" do
it "assigns a newly created but unsaved item as #item" do
post :create, { list_id: list.id, item: invalid_item_attributes, format: :json }
expect(assigns(:item)).to be_a_new(Item)
end
it "returns unprocessable_entity status" do
put :create, { list_id: list.id, item: invalid_item_attributes, format: :json }
expect(response.status).to eq(422)
end
end # "with invalid params"
end # "POST #create"
I've received the same error and fixed it in a different way. I'm using Rails ~> 5.0.7.
ROUTES
This is the output from running rake routes CONTROLLER=bills:
Prefix Verb URI Pattern Controller#Action
download_site_bill GET /sites/:site_id/bills/:id/download(.:format) bills#download
site_bills GET /sites/:site_id/bills(.:format) bills#index
POST /sites/:site_id/bills(.:format) bills#create
new_site_bill GET /sites/:site_id/bills/new(.:format) bills#new
edit_site_bill GET /sites/:site_id/bills/:id/edit(.:format) bills#edit
site_bill GET /sites/:site_id/bills/:id(.:format) bills#show
PATCH /sites/:site_id/bills/:id(.:format) bills#update
PUT /sites/:site_id/bills/:id(.:format) bills#update
DELETE /sites/:site_id/bills/:id(.:format) bills#destroy
bills GET /bills(/page/:page)(.:format) bills#index
download_bill GET /bills/:id/download(.:format) bills#download
GET /bills(.:format) bills#index
POST /bills(.:format) bills#create
new_bill GET /bills/new(.:format) bills#new
edit_bill GET /bills/:id/edit(.:format) bills#edit
bill GET /bills/:id(.:format) bills#show
PATCH /bills/:id(.:format) bills#update
PUT /bills/:id(.:format) bills#update
DELETE /bills/:id(.:format) bills#destroy
REFERENCE CODE
# controllers/admin/bills_controller.rb (excerpt)
module Admin
class BillsController < ApplicationController
...
def edit
authorize(#bill)
end
end
end
# spec/controllers/admin/bills_controller_spec.rb (excerpt)
require 'rails_helper'
RSpec.describe Admin::BillsController, type: :controller do
...
context 'as an AdminUser' do
login_admin_user
it 'loads the bill edit page' do
request.host = 'admin.example.com'
get :edit, { id: bill }
expect(response.status).to eq(200)
end
end
end
end
# Error message
2) Admin::BillsController GET bills/:id/edit as a User redirects to the home page
Failure/Error: get :edit
ActionController::UrlGenerationError:
No route matches {:action=>"edit", :controller=>"admin/bills"}
POTENTIAL SOLUTION
I tried variations of this solution. It may work for others, but I got this error:
Failure/Error: require 'admin/bills_controller'
LoadError:
cannot load such file -- admin/bills_controller
SOLUTION
I tried Case 2 in this github issues and it worked. The changes I made to my code were to add this params: { use_route: 'admins/bills/', id: bill.id }. Below is the context of this addition:
context 'as an AdminUser' do
login_admin_user
it 'loads the bill edit page' do
request.host = 'admin.example.com'
get :edit, params: { use_route: 'admins/bills/', id: bill.id }
expect(response.status).to eq(200)
end
end
As I added tests to my spec, I became suspicious about every single one passing just as I wrote it, so I added some syntax errors into the code. It turned out, Rspec was not running my recent tests so the syntax errors weren't getting picked up. The comment in the code below shows the arbitrary line at which Rspec stopped showing a green period or red F for a test:
require 'spec_helper'
describe Api::PagesController do
def valid_session
{}
end
describe "GET index" do
before :each do
#page = create(:page)
end
it "assigns all pages as #pages" do
get :index
assigns(:pages).should eq([#page])
end
it "returns json" do
get :index, format: :json
expect(response.body).to have_content #page.to_json
end
end
describe "GET show" do
before :each do
#page = create(:page)
end
it "assigns the requested page as #page" do
get :show, {:id => #page.to_param}, valid_session
assigns(:page).should eq(#page)
end
it "returns json" do
get :show, {:id => #page.to_param}, valid_session, format: :json
expect(response.body).to have_content #page.to_json
end
end
describe "GET new" do
it "assigns a new page as #page" do
get :new, {}, valid_session
assigns(:page).should be_a_new(Page)
end
end
describe "GET edit" do
before :each do
#page = create(:page)
end
it "assigns the requested page as #page" do
get :edit, {:id => #page.to_param}, valid_session
assigns(:page).should eq(#page)
end
it "returns json" do
get :edit, {:id => #page.to_param}, valid_session, format: :json
expect(response.body).to have_content #page.to_json
end
end
describe "POST create" do
describe "with valid params" do
it "creates a new Page in the database" do
expect {
post :create, {page: attributes_for(:page)}, valid_session
}.to change(Page, :count).by(1)
end
it "assigns a newly created page as #page" do
post :create, {page: attributes_for(:page)}, valid_session
assigns(:page).should be_a(Page)
assigns(:page).should be_persisted
end
#################### TESTS BELOW HERE ARE NOT SHOWN BY RSPEC ##########
it "returns json" do
expect{
post :create, {page: attributes_for(:page)}, valid_session
}.to have_content page.to_json
end
end
describe "with invalid params" do
it "does not save the new page in the database" do
expect {
post :create, {page: attributes_for(:page_invalid)}, valid_session
}.to_not change(Page, :count).by(1)
end
#FUTURE TEST - redirects to new page with errors
end
end
describe "PUT update" do
before :each do
#page = create(:page)
end
describe "with valid params" do
it "updates the requested page" do
Page.any_instance.should_receive(:update_attributes).with({ "title" => "MyString" })
put :update, {:id => #page.to_param, :page => { "title" => "MyString" }}, valid_session
end
it "assigns the requested page as #page" do
put :update, {:id => #page.to_param, :page => { "title" => "MyString" }}, valid_session
assigns(:page).should eq(#page)
end
it "returns json" do
put :update, {:id => #page.to_param, :page => { "title" => "MyString" }}, valid_session, format: :jason
expect(response.body).to have_content #page.to_json
end
end
describe "with invalid params" do
it "assigns the page as #page" do
# Trigger the behavior that occurs when invalid params are submitted
Page.any_instance.stub(:save).and_return(false)
put :update, {:id => #page.to_param, page: attributes_for(:page_invalid)}, valid_session
assigns(:page).should eq(#page)
end
#FUTURE TEST - redirects to edit
end
end
describe "DELETE destroy" do
before :each do
#page = create(:page)
end
it "destroys the requested page" do
expect {
delete :destroy, {:id => #page.to_param}, valid_session
}.to change(Page, :count).by(-1)
end
end
describe "GET published" do
before :each do
#page = create(:page)
#page_unpublished = create(:page_unpublished)
end
it "returns a list of published pages only" do
get :published, format: :json
assigns(:pages).should eq([#page])
expect(response.body).to have_content #page_unpublished.to_json
end
end
describe "GET unpublished" do
before :each do
#page = create(:page)
#page_unpublished = create(:page_unpublished)
end
it "returns a list of unpublished pages only" do
get :unpublished, format: :json
assigns(:pages).should eq([#page_unpublished])
expect(response.body).to have_content #page_unpublished.to_json
end
end
describe "GET total_words" do
before :each do
#page = create(:page)
end
it "returns a list of unpublished pages only" do
get :total_words, {:id => #page.to_param}, format: :json
assigns(:total_words).should eq([#page_unpublished])
expect(response.body).to have_content #page_unpublished.to_json
end
end
end
When I intentionally added syntax errors to earlier tests, I saw red Fs instead of the green dots, but no error was being reported. Earlier, when there was an error, I'd see (for example):
16:10:14 - INFO - Running: spec/models/page_spec.rb
Running tests with args ["--drb", "-f", "progress", "-r", "/Users/user/.rvm/gems/ruby-1.9.3-p194/gems/guard-rspec-1.2.1/lib/guard/rspec/formatters/notification_rspec.rb", "-f", "Guard::RSpec::Formatter::NotificationRSpec", "--out", "/dev/null", "--failure-exit-code", "2", "spec/models/page_spec.rb"]...
.......F
Failures:
1) Page Publishing returns unpublished pages
Failure/Error: expect(Page.unpublished).to eq [page_unpublished]
NameError:
undefined local variable or method `page_unpublished' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_4:0x0000010355b8c0>
# ./spec/models/page_spec.rb:58:in `block (3 levels) in <top (required)>'
Finished in 0.54212 seconds
8 examples, 1 failure
Failed examples:
rspec ./spec/models/page_spec.rb:57 # Page Publishing returns unpublished pages
Done.
Now, when a test fails, I only see:
17:55:26 - INFO - Running: spec/controllers/pages_controller_spec.rb
Running tests with args ["--drb", "-f", "progress", "-r", "/Users/user/.rvm/gems/ruby-1.9.3-p194/gems/guard-rspec-1.2.1/lib/guard/rspec/formatters/notification_rspec.rb", "-f", "Guard::RSpec::Formatter::NotificationRSpec", "--out", "/dev/null", "--failure-exit-code", "2", "spec/controllers/pages_controller_spec.rb"]...
.....FF..Done.
This change happened at a pretty arbitrary time while coding, I didn't modify the Guardfile or any Spork configuration details. Any idea why this is happening?
It looks like one of the arguments to rspec is --out /dev/null. So your output is being redirected from STDOUT.
One possibility is that this is being caused by one or more bad tests. Have you tried commenting out various tests to see if you can isolate the problematic ones? If you're running your tests in order, I'd start with the ones just before and after the point at which rspec exits prematurely.