I have problem with my feature test for users creating new content. It passes only when I comment or delete this line in my controller. It looks like factory :user doesn't have ability to create new content. I checked factory using seperate test to check if it has ability to create new word and it has. What can be problem here?
authorize! :create, #word, :message => "Musisz się zalogować, aby dodać nowe słówko."
words_controller.rb
def create
authorize! :create, #word, :message => "Musisz się zalogować, aby dodać nowe słówko."
#user = current_user
#word = #user.words.build(word_params)
respond_to do |format|
if #word.save
format.html {
redirect_to new_word_path
flash[:notice] = 'Słówko zostało prawidłowo zapisane. Dodaj następne!'
}
format.json { render :show, status: :created, location: #word }
else
format.html { render :new }
format.json { render json: #word.errors, status: :unprocessable_entity }
end
end
end
user_creates_word_spec.rb
require 'spec_helper'
feature 'User creates word' do
before(:all) do
category = FactoryGirl.create(:category)
10.times { word = FactoryGirl.create(:word) }
sign_in
expect(page).to have_content 'Wyloguj się'
visit game_words_path
click_link('Dodaj słówko')
end
scenario 'with valid input' do
fill_in 'Angielski', with: 'house'
fill_in 'Polski', with: 'dom'
find(:css, ".check_boxes[value='1']").set(true)
click_button 'Zapisz'
expect(page).to have_content 'Słówko zostało prawidłowo zapisane.'
end
end
test to check if user factory has ability to create new word
it "can create new word" do
user = FactoryGirl.create(:user)
ability = Ability.new(user)
word = Word.new(user: user)
expect { ability.should be_able_to(:create, word)}
end
I changed this lines:
authorize! :create, #word, :message => "Musisz się zalogować, aby dodać nowe słówko."
#user = current_user
#word = #user.words.build(word_params)
to:
#user = current_user
#word = #user.words.build(word_params)
authorize! :create, #word, :message => "Musisz się zalogować, aby dodać nowe słówko."
And it works fine. In the previous version variable #word was definied after authorize! method, so it doesn't work properly.
Related
I'm trying to do a really simple request spec for testing my API methods in my application. Right now I'm getting 302 message when I should be getting 200 with this test.
The spec:
require 'spec_helper'
describe UsersController do
describe "#create" do
it "creates a new user " do
post '/users', user: FactoryGirl.attributes_for(:user)
expect(response.status).to eq 200
end
end
end
The factory:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:username) { |n| "Person#{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
end
end
The controller method:
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
What am I missing?
So you need to make the asynchronous post request, it should be something like below,
it "creates a new user " do
xhr :post, '/users', user: FactoryGirl.attributes_for(:user)
expect(response.status).to eq 200
end
Try this, it might work
To solve the issue I need to add the ACCEPT header to my request, like so:
post "/users", { user: #user } , { accept: 'application/json' }
Doing this fixed the issue which was the server not interpreting the request as expecting json in return.
I'm using RSpec, and I get this error when running tests:
Failure/Error: before { get edit_job_path(job) }
NoMethodError:
undefined method `jobs' for nil:NilClass
# ./app/controllers/jobs_controller.rb:63:in `correct_user'
# ./spec/requests/authentication_pages_spec.rb:35:in `block (6 levels) in <top (required)>'
The actual behavior of the page (when doing rails server) seems fine. Why is the test not working? I'm still a beginner to Ruby/Rails, so any help would be appreciated.
Some code for help:
authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "signin" do
[...]
describe "authorization" do
describe "for non-signed in users" do
describe "when attempting to visit a protected page" do
let(:user) { FactoryGirl.create(:user) }
let(:job) { FactoryGirl.create(:job, user: user) }
before { get edit_job_path(job) }
it { should_not have_content('Editing job') }
describe "after signing in" do
[...]
end
[...]
end
end
[...]
end
end
end
jobs_controller.rb
class JobsController < ApplicationController
before_action :signed_in_user, only: [:new, :create, :update]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :set_job, only: [:show, :edit, :update, :destroy]
def index
#jobs = Job.all
end
def show
end
def new
#job = Job.new
end
def edit
end
def create
#job = current_user.jobs.build(job_params)
respond_to do |format|
if #job.save
format.html { redirect_to #job, notice: 'Job was successfully created.' }
format.json { render action: 'show', status: :created, location: #job }
else
format.html { render action: 'new' }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #job.update(job_params)
format.html { redirect_to #job, notice: 'Job was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
def destroy
#job.destroy
respond_to do |format|
format.html { redirect_to jobs_url }
format.json { head :no_content }
end
end
private
def set_job
#job = Job.find(params[:id])
end
def job_params
params.require(:job).permit(:title, :org, :internship, :postdate, :filldate, :location, :link, :description)
end
def correct_user
#job = current_user.jobs.find_by(id: params[:id])
redirect_to root_url, notice: 'You can only edit your own jobs.' if #job.nil?
end
end
factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Johnny #{n}" }
sequence(:email) { |n| "johnny_#{n}#example.com" }
password "sampleton"
password_confirmation "sampleton"
end
factory :job do
sequence(:title) { |n| "Example Title #{n}" }
user
end
end
sessions_helper.rb
module SessionsHelper
[...]
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
[...]
def signed_in?
!current_user.nil?
end
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
[...]
def store_location
session[:return_to] = request.url if request.get?
end
[...]
end
Your test seems to be working fine in that they've uncovered a bug. Your action expects that current_user be set, and it isn't, so you're getting an error.
You need a before_filter which redirects you when you hit a page that requires authorization.
I asked about my Rspec test as follow.
Rspec - RuntimeError: Called id for nil, which would mistakenly be 4
On the same code (Rspec test for "items_controller.rb"), I am trying to make the test for "PUT update". However I got the error "Paperclip::AdapterRegistry::NoHandlerError: No handler found for "#".
My Rspec test is as follow. Honestly, I guess that the cause of this fail is ""photo" => File.new(Rails.root + 'app/assets/images/rails.png')" on "let(:valid_attributes)". However, I tried several ways but I couldn't fix.
By the way, my rails version is "Rails 3.2.14". Then I tried following post, but also couldn't.
Can't figure out what's causing my tests to fail
The error is as follows.
......F....
Failures:
1) ItemsController PUT update could not update successfully
Failure/Error: put :update, {:id => item.to_param, :item => valid_attributes}, valid_session
Paperclip::AdapterRegistry::NoHandlerError:
No handler found for "#<File:0x5d4c548>"
# ./app/controllers/items_controller.rb:110:in `block in update'
# ./app/controllers/items_controller.rb:108:in `update'
# ./spec/controllers/items_controller_spec.rb:95:in `block (3 levels) in <top (required)>'
Finished in 1.75 seconds
11 examples, 1 failure
Failed examples:
rspec ./spec/controllers/items_controller_spec.rb:91 # ItemsController PUT update could not update successfully
Randomized with seed 40912
My Rspec test is as follows.
require 'spec_helper'
require 'date'
describe ItemsController do
let(:valid_attributes) { {
"days" => "1",
"hours" => "1",
"minutes" => "1",
"name"=>"HogeHoge" ,
"category" => "Gift",
"min_bid_price" => "100.0",
"description" => "HogeHoge",
"photo" => File.new(Rails.root + 'app/assets/images/rails.png')
} }
let(:valid_session) { {} }
it "returns http success" do
get "index"
response.should be_success
end
it "returns http success" do
get "new"
response.should be_success
end
describe "POST create" do
it "" do
#declare the objects and stubs
current_user = User.new(id:'1')
current_user.save
#"current_user=(user)" function on controller
controller.current_user = current_user
#auction
auction = Auction.new(id:'1',highest_bid_id:'1', extend_bit:'1')
auction.save
Auction.stub(:find_by_id).and_return(auction)
#bid
bid = Bid.new(auction_id:'1',amount:'150.0')
bid.save
Bid.stub(:find_by_id).and_return(bid)
#item
item = Item.new(id:'1',auction_id:'1',min_bid_price:'100.0')
item.save
Item.stub(:find_by_id).and_return(item)
date = DateTime.now
post :create, {:item => {'id' => '2','days'=>'1','hours'=>'1','minutes'=>'1','created_at'=>date}}
response.should be_success
end
end
describe "GET index" do
it "assigns all items as #items" do
item = Item.create! valid_attributes
get :index, {}, valid_session
assigns(:items).should eq([item])
end
end
describe "GET show" do
it "assigns the requested item as #item" do
item = Item.create! valid_attributes
get :show, {:id => item.to_param}, valid_session
assigns(:item).should eq(item)
end
end
describe "GET new" do
it "assigns a new item as #item" do
get :new, {}, valid_session
assigns(:item).should be_a_new(Item)
end
end
describe "GET edit" do
it "assigns the requested item as #item" do
item = Item.create! valid_attributes
get :edit, {:id => item.to_param}, valid_session
assigns(:item).should eq(item)
end
end
describe "PUT update" do
it "could not update successfully" do
item = Item.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
Item.any_instance.stub(:save).and_return(false)
put :update, {:id => item.to_param, :item => valid_attributes}, valid_session
assigns(:item).should eq(item)
response.should redirect_to(#item)
end
it "could not update successfully" do
item = Item.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
Item.any_instance.stub(:save).and_return(false)
put :update, {:id => item.to_param, :item => { }}, valid_session
response.should render_template("edit")
end
end
describe "DELETE destroy" do
it "destroys the requested item" do
item = Item.create! valid_attributes
expect {
delete :destroy, {:id => item.to_param}, valid_session
}.to change(Item, :count).by(-1)
end
it "redirects to the items list" do
item = Item.create! valid_attributes
delete :destroy, {:id => item.to_param}, valid_session
response.should redirect_to(items_url)
end
end
end
My "items_controller.rb" is as follw.
require 'timers'
class ItemsController < ApplicationController
#instance of current user
def current_user=(user)
#current_user ||= user
end
def extendtimer
Auction.find_by_id(#auction_id).update_attributes(:extend_bit => 0)
#exp = Auction.find_by_id(#auction_id).exp_time + 2.minutes
Auction.find_by_id(#auction_id).update_attributes(:exp_time => #exp)
#min = Item.find_by_id(#item_id).minutes + 2
Item.find_by_id(#item_id).update_attributes(:minutes => #min)
#timer2 = Timers.new
#extend_timer = #timer2.after(120){ buy }
#timer2.wait
end
def buy
if Auction.find_by_id(#auction_id).extend_bit == 1
extendtimer
else
if Auction.find_by_id(#auction_id).highest_bid_id != 0
Item.find_by_auction_id(#auction_id).update_attributes(:sold => 1, :sold_to => Bid.find_by_id(Auction.find_by_id(#auction_id).highest_bid_id).user_id )
MyMailer.auction_winner_email(Auction.find_by_id(#auction_id)).deliver
else
Item.find_by_auction_id(#auction_id).update_attributes(:sold => 0, :sold_to => 0 )
MyMailer.no_bids_email(Auction.find_by_id(#auction_id)).deliver
end
#t1.join
end
end
def index
#items = Item.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #items }
end
end
# GET /items/1
# GET /items/1.json
def show
#item = Item.find(params[:id])
respond_to do |format|
#format.html # show.html.erb
format.html { render layout: (request.headers["X-Requested-With"] != 'XMLHttpRequest') }
format.json { render json: #item }
end
end
# GET /items/new
# GET /items/new.json
def new
#item = Item.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #item }
end
end
# GET /items/1/edit
def edit
#item = Item.find(params[:id])
end
# POST /items
# POST /items.json
def create
#item = Item.new(params[:item])
#item.user_id = current_user.id
respond_to do |format|
if #item.save
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render json: #item, status: :created, location: #item }
else
format.html { render action: "new" }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
#elapsed_seconds =(((params[:item][:days].to_i * 24)+params[:item][:hours].to_i)*60+params[:item][:minutes].to_i)*60
#auction = Auction.create(:item_id => #item.id, :highest_bid_id => 0, :exp_time => #item.created_at+ #elapsed_seconds.seconds, :suspend => 0, :user_id => #current_user.id, :extend_bit => 0 )
#item.update_attributes(:auction_id => #auction.id)
#item_id = #item.id
#auction_id = #auction.id
#t1 = Thread.new{
#timer = Timers.new
#bid_timer = #timer.after(#elapsed_seconds){
if Auction.find_by_id(#auction_id).suspend != 1
buy
end
}
#timer.wait
}
end
# PUT /items/1
# PUT /items/1.json
def update
#item = Item.find(params[:id])
respond_to do |format|
if #item.update_attributes(params[:item])
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.json
def destroy
#item = Item.find(params[:id])
#item.destroy
respond_to do |format|
format.html { redirect_to items_url }
format.json { head :no_content }
end
end
end
I would like to have someone's advice. Thank you in advance.
Try using Rack::Test::UploadedFile instead of File.new
require 'rack/test'
Rack::Test::UploadedFile.new('fixtures/test_file.png', 'image/png')
im pretty sure your problem is with the form_for in the view,
try something like this:
<%= form_for #restaurante, :html => { :multipart => true } do |form| %>
Nome:<%= form.text_field :nome%>
Endereço:<%= form.text_field :endereco %>
Especialidade:<%= form.text_field :especialidade %>
Foto:<%= form.file_field :foto %>
<%= form.submit 'create'%>
<% end %>
Make sure it's multipart/form-data in the test.
I have a helper method for this.
module Support
module Acceptance
module ClassMethods
def multipart_form_data!
header 'Accept', 'application/json'
header 'Content-Type', 'multipart/form-data'
end
end
end
end
I have controllers - Survey, Questions and Options.
I cannot save Survey without creating Questions first. And in turn Questions cannot be created creating Options first. How to get "create" specs pass for Survey controller...
Surveys_Controller_spec.rb
describe "POST 'create'" do
before(:each) do
#user = FactoryGirl.create(:activated_user)
login_user(#user)
end
context "with valid parameters" do
let(:parameters) { { :title => "Title of the Survey", :description => "description", :activated => "false", :participant_info => "0", :is_draft => "true", :thank_you_message => "Thank You", :user_id => #user.id } }
it "creates a new survey" do
expect { post :create, :survey => parameters }.to change(Survey, :count).by(1)
end
Surveys_Controller.rb
def create
#survey = convert_enums(current_user.surveys.new(params[:survey]), params)
respond_to do |format|
if #survey.save
format.html { redirect_to dashboard_path, :notice => "Survey was successfully created!"}
else
format.html { render :new }
end
end
I am setting a user through modifying the params instead of creating a hidden_field in the form. As far as I understand, this is a more secure way of handling mass-assignment.
def update
#exercise = Exercise.find(params[:id])
#this is the important part
if params[:exercise][:log_entries_attributes].present?
params[:exercise][:log_entries_attributes].each do |value|
value[1].merge!(:user_id => current_user.id)
end
end
#end the important part
respond_to do |format|
if #exercise.update_attributes(params[:exercise])
format.html { redirect_to_back_or_default #exercise, notice: "Exercise was successfully updated." }
format.mobile { redirect_to #exercise, notice: 'Exercise was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.mobile { redirect_to #exercise, notice: "#{#exercise.errors.full_messages.to_sentence}" }
format.json { render json: #exercise.errors, status: :unprocessable_entity }
end
end
end
In my spec I have the following:
describe "with log_entry_attributes" do
it "updates log_entries_attributes and sets user" do
exercise = FactoryGirl.create(:exercise)
log_entry = FactoryGirl.build(:log_entry)
exercise.log_entries << log_entry
exercise.save
controller.stub(:current_user).and_return(#user)
put :update, :id => exercise.id, :exercise => FactoryGirl.build(:exercise, "log_entries_attributes" => {":0" => {"reps" => "5", "weight" => "5"}}).attributes.symbolize_keys
assigns(:exercise).log_entries.first.user.should eq(#user)
end
end
I get undefined method user for nil:NilClass. I think I know why I get undefined method user. There's just no way to get the association through assigns. I'm not sure how to test that the user_id is being set properly through the current_user. Any help?
Work with mocked object:
exercise = double "exercise"
Exercise.should_receive(:find).and_return(exercise)
and test with:
exercise.should_receive(:update_attributes).with(correct_params)