(Rspec) expected #count to have changed by 1, but was changed by 0 - ruby-on-rails-5

I started to learn Rspec one day ago. When writing test for my articles controller, I got error at create new article. Here is my controller:
def create
Article.transaction do
begin
#article = Article.new(article_params)
respond_to do |format|
if #article.save
view_context.create_sitemap
flash[:show_alert] = true
format.html { redirect_to edit_admin_article_path(#article), notice: 'Created sucessfull' }
else
format.html { render :new }
format.json { render json: #article.errors,notice: "Unprocessable entity" }#may need a helper to handle exception
end
end
rescue Exception => e
raise ActiveRecord::Rollback
respond_to do |format|
flash[:show_alert] = true
format.html { redirect_to new_admin_article_path, notice: 'Create failed'}
end
end
end
end
here is my test:
describe "POST #create" do
context "with valid attributes" do
it "creates a new article" do
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to change(Article, :count).by(1)
end
it "redirects to the index page" do
post :create, params: { article: FactoryGirl.attributes_for(:article) }
expect(response).to redirect_to admin_articles_path
end
end
context "with invalid attributes" do
it "does not save the new article" do
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to_not change(Article, :count).by(1)
end
it "re-renders the :new template" do
post :create, params: { article: FactoryGirl.attributes_for(:article) }
expect(response).to render_template :new
end
end
end
And here is the log:
3) Admin::ArticlesController POST #create with valid attributes creates a new article
Failure/Error:
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to change(Article, :count).by(1)
expected #count to have changed by 1, but was changed by 0
# ./spec/controllers/admin/articles_controller_spec.rb:29:in `block (4 levels) in <top (required)>'
I spent time to search for the same issue but, all of them didn't solve my error. My problem is I cannot find out where the error come from. Any help is appreciated.

Related

Ruby on rails with paperclip

I am a new programmer on ruby on rails, and i have problem when upload picture. Deos anyone can help me. thanks in advance.
class StudentsController < ApplicationController
before_action :set_student, only: [:show, :edit, :update, :destroy]
# GET /students
# GET /students.json
def index
#students = Student.all
end
# GET /students/1
# GET /students/1.json
def show
end
# GET /students/new
def new
#student = Student.new
end
# GET /students/1/edit
def edit
end
# POST /students
# POST /students.json
def create
#student = Student.create(student_params)
respond_to do |format|
if #student.save
format.html { redirect_to #student, notice: 'Student was successfully created.' }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
private
#def student_params
#params.require(:student).permit(:image_file)
#end
# PATCH/PUT /students/1
# PATCH/PUT /students/1.json
def update
respond_to do |format|
if #student.update(student_params)
format.html { redirect_to #student, notice: 'Student was successfully updated.' }
format.json { render :show, status: :ok, location: #student }
else
format.html { render :edit }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
# DELETE /students/1
# DELETE /students/1.json
def destroy
#student.destroy
respond_to do |format|
format.html { redirect_to students_url, notice: 'Student was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_student
#student = Student.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def student_params
params.require(:student).permit(:name, :gender, :telephone, :address)#, :image_file
end
end
Can't really find a problem in your post. It's a bit hard to understand. Did you follow the docs on https://github.com/thoughtbot/paperclip? I take it your file attachment is in the Student model?
params.require(:student).permit(:name, :gender, :telephone, :address)#, :image_file
now you only permit to save name, gender, telephone and address, the image file wil not be saved. You still have to permit it.

Rspec2 nested resources broken redirect

I'm trying to write a Rspec test for my nested autolinks_controller. However, the redirect after my create action is broken. After successfully creating an autolink I want to be redirected to that autolink within a particular website (hence, website_autolink_path). My controller spec looks like this:
describe "POST create when params[:website_id] are present" do
before(:each) do
#website = create(:website)
#autolink = attributes_for(:website_autolink, website_id: #website.id)
end
context "with valid attributes and params[:website_id] are present" do
it "saved the autolink in the database" do
expect{
post :create, website_id: #website, autolink: attributes_for(:website_autolink)
}.to change(Autolink, :count).by(1)
end
it "redirects to the 'index' page" do
post :create, website_autolink: #autolink, website_id: #website
response.should redirect_to website_autolink_path
end
end
end
This line is not working:
response.should redirect_to website_autolink_path
Giving me the error message:
ActionController::RoutingError:
No route matches {:action=>"show", :controller=>"autolinks"}
My factories look like this:
Autolink:
FactoryGirl.define do
factory :website_autolink do
name "MyName"
url "http://www.myurl.nl"
association :website
end
end
Website:
FactoryGirl.define do
factory :website do
name "Test"
domain "http://www.test.nl"
end
end
My AutolinkController:
def create
if params[:website_id].present?
#website = Website.find(params[:website_id])
#autolink = #website.autolinks.create(params[:autolink])
else
#autolink = Autolink.new(params[:autolink])
end
respond_to do |format|
if #autolink.save
if params[:website_id].present?
format.html { redirect_to [#website, #autolink], notice: "Autolink is met succes aangemaakt." }
else
format.html { redirect_to autolinks_path, notice: "Autolink is met succes aangemaakt." }
end
format.json { head :no_content }
else
format.html { render action: "new" }
format.json { render json: #autolink.errors, status: :unprocessable_entity }
end
end
end
Within my controller, the following line is the one I want to simulate using Rspec:
format.html { redirect_to [#website, #autolink], notice: "Autolink is met succes aangemaakt." }
In my localhost it's all working, but writing the actual test for this nested route troubles me.
I just found a solution for my problem. My controller spec for the create action now looks like this:
describe "POST create when params[:website_id] are present" do
context "with valid attributes and params[:website_id] are present" do
before(:each) do
#website = create(:website)
#autolink = attributes_for(:website_autolink, website: #website)
end
it "saved the autolink in the database" do
expect{
post :create, autolink: #autolink, website_id: #website.id
}.to change(Autolink, :count).by(1)
end
it "redirects to the 'index' page" do
post :create, autolink: #autolink, website_id: #website.id
response.should redirect_to website_autolink_path(#website, assigns(:autolink))
end
end
end
I just had to assign my autolink in order to redirect_to the nested path. Without it, the id of my autolink couldn't be found.

How do I pass a params parameter into an rspec controller test?

I have the following rspec test:
def valid_attributes
{ "product_id" => "1" }
end
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, {:line_item => valid_attributes}, valid_session #my valid_session is blank
}.to change(LineItem, :count).by(1)
end
Which fails with this error:
1) LineItemsController POST create with valid params redirects to the created line_item
Failure/Error: post :create, {:line_item => valid_attributes}, valid_session
ActiveRecord::RecordNotFound:
Couldn't find Product without an ID
# ./app/controllers/line_items_controller.rb:44:in `create'
# ./spec/controllers/line_items_controller_spec.rb:87:in `block (4 levels) in <top (required)>'
This is my controller's create action:
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.line_items.build(:product => product)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render json: #line_item.cart, status: :created, location: #line_item }
else
format.html { render action: "new" }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
As you can see, my action expects a product_id from the request's params object. How should I work this product_id into my rspec test?
I've tried placing this before statement:
before(:each) do
ApplicationController.any_instance.stub(:product).and_return(#product = mock('product'))
end
. . . but it changes nothing. I am missing some rspec concept here somewhere.
Try like this:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => 1
}.to change(LineItem, :count).by(1)
end
Hope it helps.
I ended up resolving my issue by using a fixture instead of attempting to mock the solution as suggested in another answer.
The reason for this is that the controller does the query to get information from the database: product = Product.find(params[:product_id]) and I found a fixture-based solution was quicker to resolve my problem than one using a mock and I could not figure out how to stub the query quickly (the fixtures also help with another test on the controller so it eventually helped anyway.
For reference:
I referenced my fixture with this line toward the top of the test: fixtures :products
I changed my test to:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => products(:one).id
}.to change(LineItem, :count).by(1)
end
And here is my fixture file, products.yml:
one:
name: FirstProduct
price: 1.23
two:
name: SecondProduct
price: 4.56

Rails3 and Rspec2 controller testing with a namespace

I'm trying to test a controller with a name space, following is my controller (/admin/sites_controller.rb):
class Admin::SitesController < AdminController
def create
#site = Site.new(params[:site])
respond_to do |format|
if #site.save
format.html { redirect_to(#site, :notice => 'Site was successfully created.') }
format.xml { render :xml => #site, :status => :created, :location => #site }
else
format.html { render :action => "new" }
format.xml { render :xml => #site.errors, :status => :unprocessable_entity }
end
end
end
end
and following is my routes.rb file
namespace :admin do
resources :sites
end
I'm using rspec2 to test my controller and following is my controller spec
describe Admin::SitesController do
describe "POST create" do
describe "with valid params" do
it "creates a new Site" do
expect {
post :create, :site => valid_attributes
}.to change(Site, :count).by(1)
end
end
end
end
But when I run the spec it gives me the following routing error
Admin::SitesController POST create with valid params creates a new Site
Failure/Error: post :create, :site => valid_attributes
NoMethodError:
undefined method `site_url' for #<Admin::SitesController:0xb5fbe6d0>
# ./app/controllers/admin/sites_controller.rb:47:in `create'
# ./app/controllers/admin/sites_controller.rb:45:in `create'
# ./spec/controllers/admin/sites_controller_spec.rb:78
# ./spec/controllers/admin/sites_controller_spec.rb:77
I guess its because of the 'admin' name space I'm using, but how can I fix that?
I'm using
Rails3
Rspec2
Linux
When you namespace the route, you're creating URL and path helpers that look like this:
HTTP Verb Path action helper
GET /admin/sites index admin_sites_path
GET /admin/sites/new new new_admin_site_path
POST /admin/sites create admin_sites_path
GET /admin/sites/:id show admin_site_path(:id)
GET /admin/sites/:id/edit edit edit_admin_site_path(:id)
PUT /admin/sites/:id update admin_site_path(:id)
DELETE /admin/sites/:id destroy admin_site_path(:id)
So you can either use those directly in your code (i.e. redirect_to admin_site_path(#site) ), or you can do something like:
redirect_to([:admin, #site])

How would you test this action in RSpec?

I'm a newbie in RSpec, I have this controller in my ruby on rails code
def create
#article = current_user.articles.build params[:article]
if #article.save
redirect_to articles_path, :notice => 'Article saved successfully!'
else
render :new
end
end
How would you test this action in RSpec ?
Thank you
describe "POST 'create'" do
let(:article) { mock_model(Article) }
before(:each) do
controller.stub_chain(:current_user,:articles,:build) { article }
end
context "success" do
before(:each) do
article.should_receive(:save).and_return(true)
post :create
end
it "sets flash[:notice]" do
flash[:notice].should == "Article saved successfully!"
end
it "redirects to articles_path" do
response.should redirect_to(articles_path)
end
end
context "failure" do
before(:each) do
article.should_receive(:save).and_return(false)
post :create
end
it "assigns #article" do
assigns(:article).should == article
end
it "renders new" do
response.should render_template('new')
end
end
end