Hartl Chap. 9.2.2 test fail - ruby

I am about to proceed to sec. 9.2.3 when all of the sudden my spec test turns to RED!!!!
what am i doing wrong?? Here are my errors:
Failures:
1) Authentication authorization as wrong user visiting Users#edit page
Failure/Error: it { should_not have_selector('title', text: full_title('Edit user')) }
expected css "title" with text "Ruby on Rails Tutorial Sample App | Edit user" not to return anything
# ./spec/requests/authentication_pages_spec.rb:72:in `block (5 levels) in <top (required)>'
2) Authentication authorization as wrong user submitting a PUT request to the Users#update action
Failure/Error: specify { response.should redirect_to(root_path) }
Expected response to be a <:redirect>, but was <200>
# ./spec/requests/authentication_pages_spec.rb:77:in `block (5 levels) in <top (required)>'
Finished in 1.57 seconds
64 examples, 2 failures
Failed examples:
rspec ./spec/requests/authentication_pages_spec.rb:72 # Authentication authorization as wrong user visiting Users#edit page
rspec ./spec/requests/authentication_pages_spec.rb:77 # Authentication authorization as wrong user submitting a PUT request to the Users#update action
authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "signin page" do
before { visit signin_path }
it { should have_selector('h1', text: 'Sign in') }
it { should have_selector('title', text: 'Sign in') }
end
describe "signin" do
before { visit signin_path }
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_selector('title', text: 'Sign in') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
end
end
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
end
describe "authorization" do
describe "for non-signed-in users" do
let(:user) { FactoryGirl.create(:user) }
describe "in the Users controller" do
describe "visiting the edit page" do
before { visit edit_user_path(user) }
it { should have_selector('title', text: 'Sign in') }
end
describe "submitting to the update action" do
before { put user_path(user) }
specify { response.should redirect_to(signin_path) }
end
end
end
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong#example.com") }
before { sign_in user }
describe "visiting Users#edit page" do
before { visit edit_user_path(wrong_user) }
it { should_not have_selector('title', text: full_title('Edit user')) }
end
describe "submitting a PUT request to the Users#update action" do
before { put user_path(wrong_user) }
specify { response.should redirect_to(root_path) }
end
end
end
end
users_controller.rb
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
private
def signed_in_user
redirect_to signin_url, notice: "Please sign in." unless signed_in?
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
end
sessions_helper.rb
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def current_user?(user)
user == current_user
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
it { should have_selector('h1', text: user.name) }
it { should have_selector('title', text: user.name) }
end
describe "signup page" do
before { visit signup_path }
it { should have_selector('h1', text: 'Sign up') }
it { should have_selector('title', text: full_title('Sign up')) }
end
describe "signup" do
before { visit signup_path }
let(:submit) { "Create my account" }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
end
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit edit_user_path(user)
end
describe "page" do
it { should have_selector('h1', text: "Update your profile") }
it { should have_selector('title', text: "Edit user") }
it { should have_link('change', href: 'http://gravatar.com/emails') }
end
describe "with invalid information" do
before { click_button "Save changes" }
it { should have_content('error') }
end
describe "with valid information" do
let(:new_name) { "New Name" }
let(:new_email) { "new#example.com" }
before do
fill_in "Name", with: new_name
fill_in "Email", with: new_email
fill_in "Password", with: user.password
fill_in "Confirm Password", with: user.password
click_button "Save changes"
end
it { should have_selector('title', text: new_name) }
it { should have_selector('div.alert.alert-success') }
it { should have_link('Sign out', href: signout_path) }
specify { user.reload.name.should == new_name }
specify { user.reload.email.should == new_email }
end
end
end
What could be the issue? The stuff is pretty much exactly what the tutorial calls for.

Change your edit action to:
def edit
#user = User.find(params[:id])
end
And the first line in your update action should also do this:
def update
#user = User.find(params[:id])
...

For others who might run into this, UsersController is missing the following:
before_action :correct_user, only: [:edit, :update]
This uses your method in the SessionsHelper and since it's done before edit and update #user = User.find(params[:id]) in edit and update the same evaluation becomes superfluous.

Related

How can i return some message if before_validation method is false by Sinatra

I want to return some message that tell the user their password is not match with the confirm password field.
This is my code
post '/signup' do
user = User.new(params[:user])
if user.create_user
"#{user.list}"
else
"password not match"
end
end
require 'bcrypt'
class User < ActiveRecord::Base
include BCrypt
# This is Sinatra! Remember to create a migration!
attr_accessor :password
validates :username, presence: true, uniqueness: true
validates :email, :format => { :with => /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i ,
:message => "Email wrong format" }
validates :email, uniqueness: true,presence: true
validates :encrypted_password, presence: true
validates :encrypted_password, length: { minimum: 6 }
before_validation :checking_confirm_password
def initialize(signup = {})
##signup = signup
super()
#username = signup["username"]
#email = signup["email"]
#password = signup["password"]
#confirm_password = signup["confirm_password"]
end
def create_user
p_p = Password.create(#password)
p_h ||= Password.new(p_p)
user_hash = {:username => #username,:email => #email, :encrypted_password => p_h}
return User.create(user_hash)
end
def list
User.all
end
private
def checking_confirm_password
if #password != #confirm_password
return false
end
end
end
So how can i specific the message that will send back to the user,
if their password is not match or the validation fail before create the dada?
Thanks!
The validations populate #user.errors with all validation errors with all validation errors by field, so you can easily return all validation errors at once like so:
post '/signup' do
user = User.new(params[:user])
if user.create_user
"#{user.list}"
else
user.errors.full_messages
end
end
Have a look at: http://edgeguides.rubyonrails.org/active_record_validations.html#working-with-validation-errors

Railstutorial.org 6.2.4 Format Validation

Working my way through Hartl's Railstutorial.org, an I run into an issue getting the test to work on the Format validation with the email.
My user.rb is as follows:
class User < ActiveRecord::Base
validates :name, presence: true, length: { maximum:50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }
end
user_spec.rb is:
require 'spec_helper'
describe User do
before do
#user = User.new(name: "Example User", email: "user#example.com")
end
subject { #user }
it { should respond_to(:name) }
it { should respond_to(:email)}
it { should be_valid}
describe "when name is not present" do
before { #user.name = " " }
it { should_not be_valid }
end
describe "when email is not present" do
before { #user.email=" "}
it { should_not be_valid }
end
describe "when name is too long" do
before { #user.name="a"*51}
it {should_not be_valid}
end
describe "when email format is invalid" do
it "should be invalid" do
addresses = %w[user#foo,com user_at_foo.org
example.user#foo. foo#bar_baz.com foo#bar+baz.com]
addresses.each do |invalid_address|
#user.email = invalid_address
expect(#user).not_to be_valid
end
end
end
describe "when email format is valid" do
it "should be valid" do
addresses = %w[user#foo.COM A_US-ER#f.b.org frst.lst#foo.jp a+b#baz.cn]
addresses.each do |valid_address|
#user.email = valid_address
expect(#user).to be_valid
end
end
end
end
My error listing is as follows:
Failures:
1) User
Failure/Error: it { should be_valid}
expected #<User id: nil, name: "Example User", email: "user#example.com",
created_at: nil, updated_at: nil> to be valid, but got errors: Email is invalid
# ./spec/models/user_spec.rb:13:in 'block (2 levels) in <top (required)>'
2) User when email format is valid should be valid
Failure/Error: expect(#user).to be_valid
expected #<User id: nil, name: "Example User", email: "user#foo.COM". cre
ated_at: nil, updated_at: nil> to be valid, but got errors. Email is invalid
# ./spec/models/user_spec.rb:45:in 'block (4 levels) in <top (required)>'
# ./spec/models/user_spec.rb:43:in 'each'
# ./spec/models/user_spec.rb:43:in 'block (3 levels) in >top (required)>'
Finished in 0.03 seconds
8 examples, 2 failures
Failed examples:
rspec ./spec/models/user_spec.rb:13 # User
rspec ./spec/models/user_spec.rb:41 # User when email format is valid should be
valid
I am sure that I am missing something minor (when I have this much trouble figuring it out, it usually is minor). Would greatly appreciate any help I can get.
The exact code in the tutorial is as follows:
class User < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }
end
your VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z]+\z/i lacks some letters.

Nested RSpec Tests

I am following Michael Hartl's tutorial and came across this following codes that I am having trouble comprehending.
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before(:each) do
sign_in user
visit users_path
end
it { should have_title('All users') }
it { should have_content('All users') }
describe "pagination" do
before(:all) { 30.times { FactoryGirl.create(:user) } }
after(:all) { User.delete_all }
it { should have_selector('div.pagination') }
it "should list each user" do
User.paginate(page: 1).each do |user|
expect(page).to have_selector('li', text: user.name)
end
end
end
end
My question is:
is this a NESTED TEST where the test block of Pagination runs inside Index Test block? in other words, the sequence of testing flow:
before(:each) outer block of signing in user and visiting user path is executed
then the inner block of 30.times { FactoryGirl.create(:user) is executed
then the inner block of it { should have_selector('div.pagination') } is executed
then the inner block of expect(page).to have_selector('li', text: user.name) is executed
thank you
Here's the flow for the above test:
The before(:each) block is executed before each of the following:
it { should have_title('All users') }
it { should have_content('All users') }
Then, the before(:each) is executed again, followed by the describe block, which executes:
before(:all) { 30.times { FactoryGirl.create(:user) } }
it { should have_selector('div.pagination') }
it "should list each user" do
User.paginate(page: 1).each do |user|
expect(page).to have_selector('li', text: user.name)
end
end
Finally, after(:all) { User.delete_all } is executed.
I hope this helps explain the flow.

When is the validator of email uniqueness trigerred?

I have a question about this test from the Michael Hartl tutorial :
Model:
class User < ActiveRecord::Base
.
.
.
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: true
end
Test:
require 'spec_helper'
describe User do
before do
#user = User.new(name: "Example User", email: "user#example.com")
end
.
.
.
describe "when email address is already taken" do
before do
user_with_same_email = #user.dup
user_with_same_email.email = #user.email.upcase
user_with_same_email.save
end
it { should_not be_valid }
end
end
My understanding of the uniqueness validator for the email is that it cannot be added twice in the database. But in this test, the User is just instantiated with a new, not a create.
So here is what I think happens:
#user = User.new (just in memory)
...
user_with_same_email = #user.dup we have two users in memory
...
user_with_same_email.save we are inserting the first user in the db, so it should be valid, and yet the test it { should_not be_valid } passes.
What am I getting wrong ?
What really happens:
In before:
#user = User.new (just in memory)
In the describe:
user_with_same_email = #user.dup we have two users in memory
user_with_same_email.save we are inserting the first user in the db, so it should be valid, and it is ! But that's not what's being tested here
In the it:
should_not be_valid calls .valid? on #user, and since we've just inserted an user with the same email, #user is not valid. And so the test passes.

How to refactor RSpec tests for API

I've got a series of RSpec tests for a Sinatra based API, and would like to refactor them to make them a little simpler and reduce repetition.
Here's an example a test for a route:
describe 'post /sections with empty data' do
before do
params = {
:site_id => site.id,
:page_id => page.id,
}
post '/sections', params, #session
end
specify { last_response.status.should == 200 }
specify { json_response['id'].should_not be_nil }
specify { json_response['type'].should == default_section_type }
end
Each test will be using the same base URL, with the same session data, the only difference is the parameters, and what the responses should be. There's at least 4 tests (GET, POST, PUT, DELETE) per route, and usually more.
Is there a way of making these tests more manageable?
Without resorting to metaprogramimng, you can use nested describe blocks to override only the parameters you want:
describe "/sessions" do
before do
send(http_method, "/sessions", params, #session)
end
describe "with POST" do
let(:http_method) { :post }
describe "and empty data" do
let(:params) do
{ :site_id => site.id, :page_id => page.id }
end
specify { last_response.status.should == 200 }
specify { json_response['id'].should_not be_nil }
specify { json_response['type'].should == default_section_type }
end
describe "with non-empty data" do
let(:params) do
# relevant params
end
end
end
describe "with GET" do
let(:http_method) { :get }
# ...
end
end
Have no idea if this works but it can give you an idea of what you can do
describe ' /sections with empty data' do
before(:all) do
#params = {
:site_id => site.id,
:page_id => page.id,
}
end
after(:each) do
specify { last_response.status.should == 200 }
specify { json_response['id'].should_not be_nil }
specify { json_response['type'].should == default_section_type }
end
[:get, :post, :put, :delete].each do |http_method|
it "works with #{http_method}" do
send(http_method) '/sections', #params, #session
end
end
end
Update
Reading your question again made me realize that this is not what you actually asked for. If it doesn't help at all tell me so I delete it.

Resources