Rspec case for rails 4 patch :update - ruby-on-rails

I am using Devise in my app, and trying to write a spec for updating email ID. The UI works, but the spec is failing. I am reloading the user object as well, before testing against changed email ID.
One thing that I do observe is that there is UPDATE USERS statement being run on the database.
What is the correct way to write the spec?
RSpec spec:
it "should update email" do
#user = subject.current_user
patch :update, id: #user, user: {:email => "john.doe#example1.com"}
#user.reload
expect(#user.email).to eq("john.doe#example1.com")
end
RSpec Error Log:
1) Users::RegistrationsController logged in user should update email
Failure/Error: expect(#user.email).to eq("john.doe#example1.com")
expected: "john.doe#example1.com"
got: "john.doe#example.com"
(compared using ==)
test.log:
ActiveRecord::SchemaMigration Load (0.4ms) SELECT "schema_migrations".* FROM "schema_migrations"
(0.2ms) BEGIN
(0.4ms) SAVEPOINT active_record_1
User Exists (0.9ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'john.doe#example.com' LIMIT 1
SQL (4.1ms) INSERT INTO "users" ("created_at", "email", "encrypted_password", "first_name", "last_name", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["created_at", Sat, 22 Jun 2013 13:12:28 UTC +00:00], ["email", "john.doe#example.com"], ["encrypted_password", "$2a$04$LIRWzphxstpCLTuZjicA..YMW.Ei2V/LlYWP32gfx39nBjhFg5tLe"], ["first_name", "John"], ["last_name", "Doe"], ["updated_at", Sat, 22 Jun 2013 13:12:28 UTC +00:00]]
(0.1ms) RELEASE SAVEPOINT active_record_1
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 457 ORDER BY "users"."id" ASC LIMIT 1
Processing by Users::RegistrationsController#update as HTML
Parameters: {"id"=>"457", "user"=>{"email"=>"john.doe#example1.com"}}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 457]]
User Exists (0.4ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'john.doe#example1.com' AND "users"."id" != 457) LIMIT 1
Rendered devise/registrations/edit.html.slim within layouts/application (0.2ms)
Completed 200 OK in 73ms (Views: 4.0ms | ActiveRecord: 1.0ms)
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 457]]
(0.2ms) ROLLBACK

Try
it "should update email" do
#user = subject.current_user
patch :update, id: #user, user: {:email => "john.doe#example1.com"}
#user.reload.email.should == "john.doe#example1.com"
end
Or alternatively
it "should update email" do
#user = subject.current_user
expect {
patch :update, id: #user, user: {:email => "john.doe#example1.com"}
#user.reload
}.to change(#user, :email).to("john.doe#example1.com")
end

Related

Cannot access user model from Devise sessions controller: [merit] no target_obj found on Rule#applies?

I have
class CustomSessionsController < Devise::SessionsController
def create
#user = resource # needed for Merit
super
end
protected
def after_sign_in_path_for(resource)
#user = resource # needed for Merit
resource.update_streak
super
And
grant_on 'custom_sessions#create', badge: :streak, level: 3, temporary: true, model_name: 'User' do |user|
puts user.inspect
user.streak.count >= 3
end
But it gives the error
[merit] no target_obj found on Rule#applies?
And I can't access the model and it doesn't grant the badge or log the user. What is wrong? I followed the guide.
https://github.com/merit-gem/merit/wiki/How-to-grant-badges-on-user-using-Devise
It's doing something.
Processing by CustomSessionsController#create as HTML
Parameters: {"utf8"=>"√", "authenticity_token"=>"gqUQjF9hfzJdQqxAAQJxv7bi+kZYwuv1NWtOP0YhkbjHKwnfa5WAb/CkRZ5c+Xi5yVlnJ2v774w3XLhTa1b1sQ==", "user"=>{"email"=>"student#gmail.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"}
User Load (6.0ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["email", "student#gmail.com"]]
(7.0ms) BEGIN
SQL (3.0ms) UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5 [["last_sign_in_at", "2018-08-09 05:38:58.345271"], ["current_sign_in_at", "2018-08-10 01:40:51.644592"], ["sign_in_count", 15], ["updated_at", "2018-08-10 01:40:51.668609"], ["id", 3]]
(25.0ms) COMMIT
Streak Load (21.0ms) SELECT "streaks".* FROM "streaks" WHERE "streaks"."user_id" = $1 LIMIT 1 [["user_id", 3]]
Redirected to http://localhost:3000/
(1.0ms) BEGIN
SQL (7.0ms) INSERT INTO "merit_actions" ("user_id", "action_method", "target_model", "target_data", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["user_id", 3], ["action_method", "create"], ["target_model", "custom_sessions"], ["target_data", "--- \n...\n"], ["created_at", "2018-08-10 01:40:53.539847"], ["updated_at", "2018-08-10 01:40:53.539847"]]
(8.0ms) COMMIT
Merit::Action Load (6.0ms) SELECT "merit_actions".* FROM "merit_actions" WHERE "merit_actions"."processed" = $1 [["processed", "f"]]
(3.0ms) BEGIN
SQL (2.0ms) UPDATE "merit_actions" SET "processed" = $1, "updated_at" = $2 WHERE "merit_actions"."id" = $3 [["processed", "t"], ["updated_at", "2018-08-10 01:40:53.581875"], ["id", 17]]
(20.0ms) COMMIT
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT 1
[merit] no target_obj found on Rule#applies?
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT 1
[merit] no target_obj found on Rule#applies?
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT 1
Completed 302 Found in 2567ms (ActiveRecord: 293.2ms)
Merit 2.4, Rails 4.2.
I tried
grant_on 'custom_sessions#create', badge: :streak, level: 3, temporary: true do
puts current_user.inspect
current_user.streak.count >= 3
end
But it gave
[merit] no target found: uninitialized constant CustomSession. base_target_finder.rb:13:in 'find'
error NameError (undefined local variable or method 'current_user'
I tried
grant_on 'custom_sessions#create', badge: :streak, level: 3, temporary: true, to: :itself do |user|
puts user.inspect
user.streak.count >= 3
end
def create
#custom_session = resource # needed for Merit
def after_sign_in_path_for(resource)
#custom_session = resource # needed for Merit
But it gave
[merit] no target found: uninitialized constant CustomSession. C:/ruby23/lib/ruby/gems/2.3.0/gems/merit-2.4.0/lib/merit/base_target_finder.rb:13:in `find'
true
Completed 500 Internal Server Error in 2181ms (ActiveRecord: 177.1ms)
NoMethodError (undefined method `streak' for true:TrueClass):
app/models/merit/badge_rules.rb:43:in `block in initialize'
I got it working with
grant_on 'custom_sessions#create', badge: :streak, level: 3, temporary: true, model_name: 'User', to: :itself do |user|
def create
super
#custom_session = resource # needed for Merit
But I don't know why because the /users/sign_in path does not have an :id parameter.
https://github.com/merit-gem/merit#how-merit-finds-the-target-object
Merit would fetch the Article object from the database, found by the :id param sent in that update action.

RSpec create action

I'm using factory_bot to create objects for organisation, but here organisations are created before create call, and because of validation create request is not processed.
it 'should increase organisation count by 1' do
expect do
post :create, params: { organisation: attributes_for(:organisation)}, xhr: true
end.to change(Organisation, :count).by(1)
end
What did I do wrong in this?
(0.6ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
(0.2ms) BEGIN
(0.2ms) SAVEPOINT active_record_1
Organisation Exists (0.7ms) SELECT 1 AS one FROM "organisations" WHERE "organisations"."name" = $1 LIMIT $2 [["name", "Organisation 2"], ["LIMIT", 1]]
Organisation Exists (0.2ms) SELECT 1 AS one FROM "organisations" WHERE "organisations"."email" = $1 LIMIT $2 [["email", "organisation#domain.com"], ["LIMIT", 1]]
SQL (0.5ms) INSERT INTO "organisations" ("name", "created_at", "updated_at", "email", "phone_number", "location") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["name", "Organisation 2"], ["created_at", "2018-01-27 05:36:13.649627"], ["updated_at", "2018-01-27 05:36:13.649627"], ["email", "organisation#domain.com"], ["phone_number", "+918292929292"], ["location", "Karur"]]
Processing by Admins::OrganisationsController#create as JS
Parameters: {"organisation"=>{"email"=>"organisation#domain.com", "location"=>"Karur", "name"=>"Organisation 2", "phone_number"=>"+918292929292"}}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 127], ["LIMIT", 1]]
(0.1ms) SAVEPOINT active_record_1
Organisation Exists (0.3ms) SELECT 1 AS one FROM "organisations" WHERE "organisations"."name" = $1 LIMIT $2 [["name", "Organisation 2"], ["LIMIT", 1]]
Organisation Exists (0.5ms) SELECT 1 AS one FROM "organisations" WHERE "organisations"."email" = $1 LIMIT $2 [["email", "organisation#domain.com"], ["LIMIT", 1]]
When I try to print the count,
it 'should increase organisation count by 1' do
p Organisation.count
login_admin
p Organisation.count
expect do
post :create, params: {organisation: attributes_for(:organisation)}, xhr: true
end.to change(Organisation, :count).by(1)
end
end
the log,
Run options: include {:full_description=>/Admins::OrganisationsController\ POST\ \#\ create\ with\ valid\ params\ should\ increase\ organisation\ count\ by\ 1/}
0
1
expected #count to have changed by 1, but was changed by 0
./spec/controllers/admins/organisations_controller_spec.rb:71:in `block (4 levels) in <top (required)>'
-e:1:in `load'
-e:1:in `<main>'
Organisation is created when admin object is created. There will an association between admin and organisation.
Show your login_admin method and factories of admin and organisation if further help needed.

Change html response to json response in rails during cross platform response

I have created cross platform form to submit data. It sends data in json format, but rails controller response it as html. So that I always get error as.
Object {readyState: 0, responseJSON: undefined, status: 0, statusText: "error"}
test.html?batch[status]=0:88
Navigated to file:///home/shital/workspace/shitalluitel.github.io/test.html?batch%5Bstatus%5D=0
Here is my rails log after my form submit...
Started POST "/batches" for 127.0.0.1 at 2017-01-13 08:55:59 +0545
Processing by BatchesController#create as HTML
Parameters: {"batch"=>{"name"=>"eight", "course_id"=>"9", "start_date"=>"2016-12-12", "end_date"=>"2016-12-14", "status"=>"1"}}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.2ms) BEGIN
Course Load (0.5ms) SELECT "courses".* FROM "courses" WHERE
"courses"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]]
SQL (0.4ms) INSERT INTO "batches" ("name", "course_id", "start_date", "end_date", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["name", "eight"], ["course_id", 9], ["start_date", Mon, 12 Dec 2016], ["end_date", Wed, 14 Dec 2016], ["created_at", 2017-01-13 03:10:59 UTC], ["updated_at", 2017-01-13 03:10:59 UTC]]
(133.8ms) COMMIT
entered to true part
Completed 200 OK in 147ms (Views: 0.8ms | ActiveRecord: 135.6ms)
You can use
render json: {your_response: "value"}, status: 200
or if you want nothing then
render :nothing => true
You can change the status base on you needs.
you can try this in the controller response will automatically varies according to your platform
respond_to do |format|
format.html { render 'filename.html'}
format.json { render json: #batches }
end

Why does this integration test with post request fail?

I have written an integration test for a signup form that writes to two tables/models. It fails with the message "Organization.count" didn't change by 1. Is there, however, a way to see with what kind of error message the test fails (the form works in development, although there is an issue with displaying error messages, so I don't understand why the test fails). So I mean the error message you would have seen if you had done the same exact thing on the server to help me find out why it didn't save the organization/user.
test "valid combined organization user signup" do
get new_path
assert_template 'organizations/new'
assert_difference ['Organization.count', 'User.count'], 1 do
post organizations_path, organization: { name: "Abc1",
bag: "aef1",
users_attributes: [email: "test#test.br",
username: "abc1",
password: "foobar",
password_confirmation: "foobar"] }
end
end
Perhaps the test log can help? I see here IS NULL LIMIT for user email and username. I don't understand why, given the test syntax...
Started POST "/organizations"
Processing by OrganizationsController#create as HTML
Parameters: {"organization"=>{"name"=>"Abc def 1", "bag"=>"adef1", "users_attributes"=>[{"email"=>"adef1#uniqu.br", "username"=>"adef1", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}]}}
[1m[36m (0.2ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mOrganization Exists (0.6ms)[0m SELECT 1 AS one FROM "organizations" WHERE LOWER("organizations"."name") = LOWER('Abc def 1') LIMIT 1
[1m[36mOrganization Exists (0.3ms)[0m [1mSELECT 1 AS one FROM "organizations" WHERE LOWER("organizations"."bag") = LOWER('adef1') LIMIT 1[0m
[1m[35mOrganization Exists (0.3ms)[0m SELECT 1 AS one FROM "organizations" WHERE LOWER("organizations"."name") = LOWER('Abc def 1') LIMIT 1
[1m[36mOrganization Exists (0.3ms)[0m [1mSELECT 1 AS one FROM "organizations" WHERE LOWER("organizations"."bag") = LOWER('adef1') LIMIT 1[0m
[1m[35mSQL (0.4ms)[0m INSERT INTO "organizations" ("name", "bag", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["name", "Abc def 1"], ["bag", "adef1"], ["created_at", "2015-06-27 16:28:56.179789"], ["updated_at", "2015-06-27 16:28:56.179789"]]
[1m[36mUser Exists (0.6ms)[0m [1mSELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT 1[0m
[1m[35m (0.6ms)[0m SELECT "users"."email" FROM "users" ORDER BY "users"."username" ASC
[1m[36mUser Exists (0.2ms)[0m [1mSELECT 1 AS one FROM "users" WHERE "users"."username" IS NULL LIMIT 1[0m
[1m[35m (0.2ms)[0m ROLLBACK TO SAVEPOINT active_record_1
The controller method is posted here: stackoverflow.com/q/31072646/4499505 (organizations_path refers to the create method)
If I compare the test log with the development log (since in development the form does work), for development it makes the post below, which seem to differ from the post in the test log. How should I adjust the test syntax to create the same post as in development?
Parameters: {"utf8"=>"✓", "authenticity_token"=>"***", "organization"=>{"name"=>"test60", "bag"=>"tes60", "users_attributes"=>{"0"=>{"email"=>"test60#example.com", "username"=>"test60", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}}, "commit"=>"Register"}
Update: To match the development log, I changed the post line within the test to:
post organizations_path, organization: { name: "Abc def 1",
bag: "adef1",
users_attributes: { "0" => {email: "adef1#uniqu.br",
username: "adef1",
password: "foobar",
password_confirmation: "foobar"}} }
end
Now in the test log it no longer has IS NULL LIMIT but it still rolls back and thus the test still fails with the same message:
[1m[35mSQL (0.5ms)[0m INSERT INTO "organizations" ("name", "bag", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["name", "Abc def 1"], ["bag", "adef1"], ["created_at", "2015-06-27 19:49:45.430750"], ["updated_at", "2015-06-27 19:49:45.430750"]]
[1m[36mUser Exists (0.4ms)[0m [1mSELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('adef1#uniqu.br') LIMIT 1[0m
[1m[35m (0.5ms)[0m SELECT "users"."email" FROM "users" ORDER BY "users"."username" ASC
[1m[36mUser Exists (0.5ms)[0m [1mSELECT 1 AS one FROM "users" WHERE LOWER("users"."username") = LOWER('adef1') LIMIT 1[0m
[1m[35m (0.2ms)[0m ROLLBACK TO SAVEPOINT active_record_1
Your test code is not the same as what your development code is doing. You need to add brackets inside of the users_attributes array:
test "valid combined organization user signup" do
get new_path
assert_template 'organizations/new'
assert_difference ['Organization.count', 'User.count'], 1 do
post organizations_path,
organization: { name: "Abc1",
bag: "aef1",
users_attributes: { "0" => { email: "test#test.br",
username: "abc1",
password: "foobar",
password_confirmation: "foobar" } } }
end
end
This is why your log says it is trying to find a user whose email IS NULL, because it wasn't able to retrieve the email attribute properly, so it just defaulted to NULL instead of test#test.br.
Edit: updated to match working syntax. OP was also reporting that once the syntax was fixed, there was an error with the User model not passing a minimum length validation on username which he fixed by simply using a longer username in the test data.

Capybara-selenium fault and redirect example.com/ when without everything is green

When I run test with gem 'selenium-webdriver' (with "describe "with valid information", :js => true do")
spec/request/post_pages_spec.rb
require 'spec_helper'
describe "Post pages" do
subject { page }
category = Category.create(name: "Food")
let(:post) { FactoryGirl.create(:post) }
describe "with valid information", :js => true do
it "should create a post" do
fill_in "Title", with: post.title
fill_in "Content", with: post.content
fill_in "Publish", with: Date.today
check "Food"
expect { click_button "Create Post" }.to change(Post, :count).by(1)
end
end
end
I getting error in spec:
Failures:
1) Post pages post creation with valid information should create a post
Failure/Error: expect { click_button "Create Post" }.to change(Post, :count).by(1)
count should have been changed by 1, but was changed by 0
# ./spec/requests/post_pages_spec.rb:35:in `block (4 levels) in <top (required)>'
log/test.log
Started POST "/posts" for 127.0.0.1 at 2012-09-08 01:54:52 +0400
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "post"=>{"title"=>"Lorem ipsum", "content"=>"Lorem ipsum", "category_ids"=>["", "1"], "publish"=>"2012-09-08"}, "commit"=>"Create Post"}
[1m[35mCategory Load (0.3ms)[0m SELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT 1 [["id", 1]]
[1m[36m (0.1ms)[0m [1mbegin transaction[0m
[1m[35mSQL (5013.9ms)[0m INSERT INTO "posts" ("content", "created_at", "publish", "title", "updated_at") VALUES (?, ?, ?, ?, ?) [["content", "Lorem ipsum"], ["created_at", Fri, 07 Sep 2012 21:54:52 UTC +00:00], ["publish", Sat, 08 Sep 2012], ["title", "Lorem ipsum"], ["updated_at", Fri, 07 Sep 2012 21:54:52 UTC +00:00]]
SQLite3::BusyException: database is locked: INSERT INTO "posts" ("content", "created_at", "publish", "title", "updated_at") VALUES (?, ?, ?, ?, ?)
[1m[36m (0.4ms)[0m [1mrollback transaction[0m
SQLite3::BusyException: cannot rollback transaction - SQL statements in progress: rollback transaction
Completed 500 Internal Server Error in 5019ms
[1m[35m (0.1ms)[0m SELECT COUNT(*) FROM "posts"
[1m[36m (0.2ms)[0m [1mrollback transaction[0m
[1m[35m (0.3ms)[0m begin transaction
[1m[36m (0.1ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.7ms)[0m INSERT INTO "posts" ("content", "created_at", "publish", "title", "updated_at") VALUES (?, ?, ?, ?, ?) [["content", "Lorem ipsum"], ["created_at", Fri, 07 Sep 2012 21:54:57 UTC +00:00], ["publish", Sat, 08 Sep 2012], ["title", "Lorem ipsum"], ["updated_at", Fri, 07 Sep 2012 21:54:57 UTC +00:00]]
[1m[36m (0.1ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
Started GET "/posts" for 127.0.0.1 at 2012-09-08 01:54:57 +0400
Processing by PostsController#index as HTML
[1m[35mPost Load (0.2ms)[0m SELECT "posts".* FROM "posts"
[1m[36mCategory Load (0.2ms)[0m [1mSELECT "categories".* FROM "categories" INNER JOIN "categorizations" ON "categories"."id" = "categorizations"."category_id" WHERE "categorizations"."post_id" = 1[0m
Rendered layouts/_navigation.html.erb (1.1ms)
Rendered layouts/_messages.html.erb (0.1ms)
Completed 200 OK in 25ms (Views: 14.8ms | ActiveRecord: 0.3ms)
[1m[35m (0.1ms)[0m SELECT COUNT(*) FROM "posts"
Started DELETE "/posts/1" for 127.0.0.1 at 2012-09-08 01:54:57 +0400
Processing by PostsController#destroy as HTML
Parameters: {"id"=>"1"}
[1m[36mPost Load (0.2ms)[0m [1mSELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1[0m [["id", "1"]]
[1m[35m (0.0ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.2ms)[0m [1mDELETE FROM "posts" WHERE "posts"."id" = ?[0m [["id", 1]]
[1m[35m (0.1ms)[0m RELEASE SAVEPOINT active_record_1
Redirected to http://www.example.com/posts
Completed 302 Found in 3ms (ActiveRecord: 0.5ms)
But when I run test WITHOUT Selenium (describe "with valid information" do)
Test is green.
Why Selenium doesn't create Post and make the test red ?
How to fix it?
Solution is a specific working of Capibara with Rspec.
I add following file to spec/support/database_cleaner.rb
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before :each do
if Capybara.current_driver == :rack_test
DatabaseCleaner.strategy = :transaction
else
DatabaseCleaner.strategy = :truncation
end
DatabaseCleaner.start
end
config.after do
DatabaseCleaner.clean
end
end
Added gem in Gemfile:
group :development, :test do
gem 'database_cleaner'
end
$> bundle install
And I add a comment to the following line in spec/spec_helper.rb
RSpec.configure do |config|
#config.use_transactional_fixtures = true
end
Test becomes green.

Resources