Currently doing Rails Unit Test, using minitest-rails.
I'm using bootstrap editable js to directly update data in view.
I having trouble asserting value correctly, got Failure result.
Only for the function that I used bootstrap editable, since it uses other way to send parameters than normal Rails update action.
Please help a look at my codes.
In my controller:
def edit_job_type
update_common_table('job_types', params[:pk], params[:name], params[:value])
end
In my included module:
def update_common_table(table, id, key, value)
begin
case table
when 'job_types'
#record = JobType.find(id)
end
case key
when 'en_name'
#record.en_name = params[:value]
edit_field = 'English Name'
end
#record.last_updated_by = session[:username]
#record.save
render json: {
status: 'success',
message: "#{edit_field} was successfully updated.",
updated_at: #record.updated_at.to_time.strftime("%a, %e %b %Y %H:%M"),
updated_by: session[:username]
}
rescue => error
render json: {status: 'error', message: error.message}
end
end
In my minitest-rails, controller:
setup do
#job_type = job_types(:waiter)
end
test "should update job_type" do
patch :edit_job_type, id: #job_type.id, job_type: { pk: #job_type.id, name: 'en_name', value: "janitor" }
assert_response :success, message: 'English Name was successfully updated.'
#job_type.reload
assert_equal "janitor", #job_type.en_name # this one FAILS, not updated value
end
In my fixtures > job_types:
waiter:
en_name: waiter
When I run rake test:
I got failure result, because the update was failed.
Expected: "New Job Type Updated"
Actual: "waiter"
Still getting the default value "waiter", instead of "janitor"
Please help to figure out how can I fixed my test.
SOLVED
Finally I've made a work around after thorough searching.
The solution was to use a XHR method since bootstrap editable uses POST method.
Before:
test "should update job_type" do
patch :edit_job_type, id: #job_type.id, job_type: { pk: #job_type.id, name: 'en_name', value: "janitor" }
assert_response :success, message: ' Successfully updated.'
#job_type.reload
assert_equal "janitor", #job_type.en_name # this one FAILS, not updated value
end
After:
test "should update job_type" do
xhr :post, :edit_job_type, format: :js, pk: #job_type.id, name: 'en_name', value: "janitor"
assert_response :success, ' Successfully updated.'
#job_type.reload
assert_equal "janitor", #job_type.en_name
end
Thanks to this tutorial, Building Rails Test
Related
I have an endpoint that responds with an object's attributes + attributes that are added from an ActiveModelSerializer. I want to write a test that checks to see if the response has keys.
Let's hypothetically say that the object (say a tree) has these keys
expected_tree_attributes = [:height, :age, :color]
How do I write this test properly? Can I write:
subject { post :obtain_tree_info, { id: tree.id } }
response = JSON.parse(subject.body)
expected(response).to include(*expected_tree_attributes)
IS that... acceptable?
Please consider to use rspec-api-matchers gem
or airborne gem
With these you can do:
# api_matchers
response = JSON.parse(subject.body)
expect(response).to be_success
expect(response).to have_json_node(:height).with(tree.height)
expect(response).to have_json_node(:age).with(tree.age)
expect(response).to have_json_node(:color).with(tree.color)
# or
expect(response).to have_json_node(:age).with("123")
Airborne
describe 'sample spec' do
it 'should validate types' do
post '/api/v1/obtain_tree_info', {id: tree.id}
expect_json_types(height: :int, age: :int_or_null, color: :string)
end
end
I'm having trouble understanding how to satisfy strong params when using button_to to do an update action. I'm trying to set an attribute called active to the value of true for an existing instance of a class called Plan.
(Note that I'm using HAML for my views here.)
This works:
= form_for(plan, remote: true) do |f|
= f.hidden_field :active, value: true
= f.submit 'set active'
But this doesn't:
= button_to "set active", plan_path(plan, active: true), method: :put, remote: true
Error
Completed 400 Bad Request in 7ms (ActiveRecord: 1.1ms)
ActionController::ParameterMissing - param is missing or the value is
empty: plan:
actionpack (4.2.1) lib/action_controller/metal/strong_parameters.rb:249:in 'require'
() Users/Rob/Sites/drexel_msis_planner/app/controllers/plans_controller.rb:77:in 'plan_params'
() Users/Rob/Sites/drexel_msis_planner/app/controllers/plans_controller.rb:45:in 'block in update'
actionpack (4.2.1) lib/action_controller/metal/mime_responds.rb:210:in 'respond_to'
() Users/Rob/Sites/drexel_msis_planner/app/controllers/plans_controller.rb:44:in 'update'
Routes
user_plans GET /users/:user_id/plans(.:format) plans#index
POST /users/:user_id/plans(.:format) plans#create
new_user_plan GET /users/:user_id/plans/new(.:format) plans#new
edit_plan GET /plans/:id/edit(.:format) plans#edit
plan PATCH /plans/:id(.:format) plans#update
PUT /plans/:id(.:format) plans#update
DELETE /plans/:id(.:format) plans#destroy
Controller
# PATCH/PUT /plans/1
def update
respond_to do |format|
if #plan.update(plan_params)
format.js { flash.now[:notice] = "Plan was successfully updated." }
end
end
end
private
def plan_params
params.require(:plan).permit(:user_id, :name, :active)
end
It seems like such a silly issue but I can't figure it out and the API documentation doesn't seem to give any clues as to why it wouldn't be working.
These are but a few of the variations that I've tried (each is followed by its accompanying error message):
= button_to "set active", plan_path(plan: plan, active: true), method: :put, remote: true
ActionController::UrlGenerationError - No route matches
{:action=>"update", :active=>true, :controller=>"plans", :plan=>#,
:user_id=>"104"} missing required keys: [:id]:
= button_to "set active", plan_path(id: plan.id, active: true), method: :put, remote: true
Completed 400 Bad Request in 17ms (ActiveRecord: 2.1ms)
ActionController::ParameterMissing - param is missing or the value is
empty: plan: actionpack (4.2.1)
lib/action_controller/metal/strong_parameters.rb:249:in `require'
= button_to "set active", plan, active: true, method: :put, remote: true
ActionController::ParameterMissing - param is missing or the value is
empty: plan: actionpack (4.2.1)
lib/action_controller/metal/strong_parameters.rb:249:in 'require'
()
Users/Rob/Sites/drexel_msis_planner/app/controllers/plans_controller.rb:77:in
'plan_params' ()
Users/Rob/Sites/drexel_msis_planner/app/controllers/plans_controller.rb:45:in
'block in update'
I was able to finally resolve this based on the information in this thread.
Instead of placing the parameters in their own hash as another argument to button_to, I included them inside of the call to the plan_path method. The first argument needs to be the model's ID, and the second argument needs to be the model's name as a key with a hash of the desired attributes as its value. (Example below):
= button_to "set active", plan_path(plan.id, plan: { active: true }), method: :put, remote: true
If you look at the submitted params the difference is that your form results in params being
{ "id" => 123, "plan" => {"active" => true}, "controller" => "...", "action" => "..."}
Whereas the second results in
{ "id" => 123, "active" => true, "controller" => "...", "action" => "..."}
And in that case params[:plan] is nil, which leads to the error you see.
There are multiple ways to fix this. You could change the submitted parameters to match what the controller currently expects, for example
button_to set_active, plan, method: :put, remote: true, params: {"plan[active]" => 1}
(You could also have the parameters be part of the form URL as you were attempting but having as form fields feels slightly more correct to me).
Alternatively, if this update action isn't used by any other forms, then change it to match the submitted data. I wouldn't normally do this - it would be very easy but your app will be easier to think about if things behave in predictable ways.
According to http://apidock.com/rails/ActionView/Helpers/UrlHelper/button_to, params should be a separate hash
= button_to "set active", plan, method: :put, remote: true, params: { :active => true }
Rails: 4.1.7
RSpec-rails version: 3.1.0
I am trying to write a request spec to test the create action for my BlogPost model. RSpec doesn't seem to like the data params that I am trying to pass in because I keep seeing the following error when running the test:
ActiveRecord::UnknownAttributeError:
unknown attribute: blog_post
RSpec code:
require 'rails_helper'
RSpec.describe BlogPost do
let!(:admin_user) { Fabricate(:admin_user) }
let!(:blog_post) { Fabricate(:blog_post) }
before { login(admin_user.email, admin_user.password) }
describe 'POST /admin/blog_posts' do
before do
post admin_blog_posts_path, blog_post: {
body: 'body text',
title: 'title text',
cover_image: '/assets/post.png',
summary: 'cool post bruh',
live_demo_url: 'livedemo.com',
live_demo_url_text: 'click here',
github_source: 'github.com/awesome'
}
end
it 'should redirect to the blog posts index page' do
expect(response).to redirect_to(admin_blog_posts_path)
follow_redirect!
end
end
end
There is something about using the word blog_post it doesn't seem to like. Because I tried changing it to an arbitrary word like so and the error went away:
post admin_blog_posts_path, someresource: {
title: 'title text'
}
Also I have a put request spec, which is also using blog_post and that works fine:
describe 'PUT /admin/blog_posts/:id' do
before do
put admin_blog_post_path(blog_post.id), blog_post: {
title: 'My new title'
}
end
...
end
So I'm not really sure why RSpec doesn't like my post admin_blog_posts_path, blog_post ... syntax. Any ideas?
Noob status over here.
In my controller create action I had:
#blog_post = BlogPost.new(permitted_params)
It was raising the error because I passed in the entire params so it read blog_post as an attribute for the BlogPost resource.
The fix: #blog_post = BlogPost.new(permitted_params[:blog_post])
I am upgrading my Rails app from Rails 3.2.8 to Rails 4.0.0 following RailsCast #415 (http://railscasts.com/episodes/415-upgrading-to-rails-4?view=asciicast) and all is good until I upgrade to strong parameters. After updating the Events controller to use strong parameters I'm able to submit a form to create a new Event (no validation errors are thrown) but all the submitted params are null and the terminal log (running locally) says,
WARNING: Can't mass-assign protected attributes for Event: street, description, host_name, event_date(1i), event_date(2i), event_date(3i), event_time(1i), event_time(2i), event_time(3i), event_time(4i), event_time(5i), event_name, end_time(1i), end_time(2i), end_time(3i), end_time(4i), end_time(5i)
so obviously I am having a mass assignment problem and the strong parameters are not working properly.
The Events controller has the following private method:
private
def event_params
params.require(:event).permit(:city, :state, :street, :zip, :description,
:host_name, :host_contact, :event_date, :event_time,
:instructions, :event_name, :end_time)
end
And the event#create action looks like (created with a scaffold):
def create
#event = Event.new(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render json: #event, status: :created, location: #event }
else
format.html { render action: "new" }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
The gemfile has the following gem included for use during the transition:
gem 'protected_attributes'
and the application.rb file has whitelist_attributes set to false (it's commented out):
# config.active_record.whitelist_attributes = true
Any help in what I'm missing to connect the dots here would be helpful. Thanks.
Having "gem 'protected_attributes'" in my gemfile was causing a conflict with redefined methods. Removed it and all was good.
I have Rails 4.2.6 and rspec 3.3.0 , devise version 3.5.8 and i have trouble to test my controller specs always getting error saying ("expected the response to have a success status code (2xx) but it was 401")
Later when i try different spec I am always getting failure message ("Your account is not enabled yet !"), any ideas ?, any help much appreciated ..
my spec:
require 'rails_helper'
describe MyController, :type => :controller
let(:user) { create(:user) }
let(:campaign) { create(:campaign, user: user) }
let!(:placement) { create(:placement, user: user, campaign: campaign, end_date: Date.today) }
before(:each) do
sign_in user
end
context "when we have no data" do
before do
get :graph_data, format: :json
#json = JSON.parse(response.body)
end
it "should be a success" do
expect(response).to have_http_status(:success)
end
end
end
I have following spec_helper:
config.include Devise::TestHelpers, :type => :controller
config.before(:each) do
DatabaseCleaner.start
end
factory defined:
FactoryGirl.define do
factory :unconfirmed_user, class: User do
sequence(:email) { |n| "john#{n}#email.com" }
sequence(:name) { |n| "John Nice #{n}" }
password 'password'
password_confirmation 'password'
factory :user do
confirmed_at Time.now.utc
factory :admin do
organisation { create(:organisation, :some_organisation) }
end
end
end
controller:
MyController < ApplicationController
def graph_data
items = current_user.items //outputs [1,2,3,45,5]
render json: items, status: :ok
end
end
routes:
GET /mycontroller/graph_data(.:format)
i found what was the issue,on User model had a method 'active_for_authentication?'
def active_for_authentication?
super && (group.include?('company-group) || is_admin? )
end
Method 'active_for_authentication?' is a Devise public method
and when it is defined in your model like (User), you change behaviour of it, and in my case it was overwritten with different behaviour,
checking for belonging user to the 'company-group' or not ..
That's why i had failure message ("Your account is not enabled yet !")