SessionController action ends in redirect_to root_path.
Doing this
def sign_in(user)
visit new_session_path
fill_in "Username or email", with: user.email
fill_in "Password", with: 'please'
click_button "Sign in"
expect(page).to have_content "Sign out"
end
gives correct redirection:
Redirected to http://www.example.com/
Completed 302 Found in 4ms (ActiveRecord: 0.2ms)
Started GET "/" for 127.0.0.1 at 2014-11-28 01:08:13 -0800
Processing by Homepages::SponsorsController#index as HTML
...
But this
def sign_in(user)
page.driver.post session_path,
'session[credential]' => user.email,
'session[password]' => 'please'
end
Doesn't redirect correctly:
Redirected to http://www.example.com/
Completed 302 Found in 12ms (ActiveRecord: 0.2ms)
Why?
In every form generated by the form_for helper method, there is a hidden field named authenticity_token that contains a token used to prevent XSS attacks.
I suspect this could be the reason you're having problems posting directly to this controller.
You need to replace the page.driver with Capybara.current_session.driver:
def sign_in(user)
driver = Capybara.current_session.driver
driver.submit :post, session_path,
'session[credential]' => user.email,
'session[password]' => 'please'
end
Related
I'm following this post about setting up authentication in the routes of my Rails 4 application.
Here is my routes.rb file:
Rails.application.routes.draw do
devise_for :employees, :controllers => { registrations: 'employees/registrations' }
devise_for :clients
authenticate :employee do
resources :quotation_requests, only: [:show, :edit,:index, :update, :destroy]
end
resources :quotation_requests, only: [:new, :create]
get '/dashboard' => 'dashboard#show', as: 'show_dashboard'
root to: 'home#index'
end
Here is my quotation_requests_controller_spec.rb file:
require 'rails_helper'
RSpec.describe QuotationRequestsController, type: :controller do
describe "GET index" do
it "renders :index template" do
get :index
expect(response).to render_template(:index)
end
it "assigns quotation requests to template" do
quotation_requests = FactoryGirl.create_list(:quotation_request, 3)
get :index
expect(assigns(:quotation_requests)).to match_array(quotation_requests)
end
end
describe "GET edit" do
let(:quotation_request) { FactoryGirl.create(:quotation_request)}
it "renders :edit template" do
get :edit, id: quotation_request
expect(response).to render_template(:edit)
end
it "assigns the requested quotation request to template" do
get :edit, id: quotation_request
expect(assigns(:quotation_request)).to eq(quotation_request)
end
end
describe "PUT update" do
let(:quotation_request) { FactoryGirl.create(:quotation_request)}
context "valid data" do
new_text = Faker::Lorem.sentence(word_count=500)
let(:valid_data) { FactoryGirl.attributes_for(:quotation_request, sample_text: new_text)}
it "redirects to quotation_request#showtemplate" do
put :update, id: quotation_request, quotation_request: valid_data
expect(response).to redirect_to(quotation_request)
end
it "updates quotation request in the database" do
put :update, id: quotation_request, quotation_request: valid_data
quotation_request.reload #need to reload the object because we have just updated it in the database so need to get the new values
expect(quotation_request.sample_text).to eq(new_text)
end
end
context "invalid data" do
let(:invalid_data) { FactoryGirl.attributes_for(:quotation_request, sample_text: "", number_of_words: 400)}
it "renders the :edit template" do
put :update, id: quotation_request, quotation_request: invalid_data
expect(response).to render_template(:edit)
end
it "does not update the quotation_request in the database" do
put :update, id: quotation_request, quotation_request: invalid_data
quotation_request.reload
expect(quotation_request.number_of_words).not_to eq(400)
end
end
end
describe "GET new", new: true do
it "renders :new template" do
get :new
expect(response).to render_template(:new)
end
it "assigns new QuotationRequest to #quotation_request" do
get :new
expect(assigns(:quotation_request)).to be_a_new(QuotationRequest)
end
end
describe "GET show" do
#this test requires that there be a quotation request in the database
let(:quotation_request) { FactoryGirl.create(:quotation_request) }
context 'invalid request' do
it "does not render :show template if an employee or client is not signed in" do
#setup
quotation_request = create(:quotation_request)
#exercise
get :show, id: quotation_request
#verification
expect(response).to_not render_template(:show)
end
end
context 'valid request' do
sign_in_proofreader
it "renders :show template if an employee or client is signed in" do
#setup
quotation_request = create(:quotation_request)
#exercise
get :show, id: quotation_request
#verification
expect(response).to render_template(:show)
end
it "assigns requested quotation_request to #quotation_request" do
get :show, id: quotation_request
expect(assigns(:quotation_request)).to eq(quotation_request)
end
end
end
describe "POST create", post: true do
context "valid data" do
let(:valid_data) {FactoryGirl.nested_attributes_for(:quotation_request)}
it "redirects to quotation_requests#show" do
post :create, quotation_request: valid_data
expect(response).to redirect_to(quotation_request_path(assigns[:quotation_request]))
end
it "creates new quotation_request in database" do
expect {
post :create, quotation_request: valid_data
}.to change(QuotationRequest, :count).by(1)
end
end
context "invalid data" do
let(:invalid_data) {FactoryGirl.nested_attributes_for(:quotation_request).merge(sample_text: 'not enough sample text')}
it "renders :new template" do
post :create, quotation_request: invalid_data
expect(response).to render_template(:new)
end
it "doesn't creates new quotation_request in database" do
expect {
post :create, quotation_request: invalid_data
}.not_to change(QuotationRequest, :count)
end
end
end
describe "DELETE destroy" do
let(:quotation_request) { FactoryGirl.create(:quotation_request) }
it "redirects to the quotation request#index" do
delete :destroy, id: quotation_request
expect(response).to redirect_to(quotation_requests_path)
end
it "delets the quotation request from the database" do
delete :destroy, id: quotation_request
expect(QuotationRequest.exists?(quotation_request.id)).to be_falsy
end
end
end
My quotation_requests_controller.rb
class QuotationRequestsController < ApplicationController
# before_action :authenticate_employee!, :only => [:show]
def index
#quotation_requests = QuotationRequest.all
end
def new
#quotation_request = QuotationRequest.new
#quotation_request.build_client
end
def edit
#quotation_request = QuotationRequest.find(params[:id])
end
def create
client = Client.find_or_create(quotation_request_params[:client_attributes])
#quotation_request = QuotationRequest.new(quotation_request_params.except(:client_attributes).merge(client: client))
if #quotation_request.save
ClientMailer.quotation_request_created(client.email, #quotation_request.id).deliver_now
redirect_to #quotation_request, notice: 'Thank you.'
else
render :new
end
end
def show
#quotation_request = QuotationRequest.find(params[:id])
end
def update
#quotation_request = QuotationRequest.find(params[:id])
if #quotation_request.update(quotation_request_params)
redirect_to #quotation_request
else
render :edit
end
end
def destroy
QuotationRequest.destroy(params[:id])
redirect_to quotation_requests_path
end
private
def quotation_request_params
params.require(:quotation_request).permit(:number_of_words, :return_date, :sample_text, :client_attributes => [:first_name, :last_name, :email])
end
end
I know the routes authentication works because if I test them in the browser I get redirected to the sign_in page. However, the tests don't pass in Rspec.
if I put this code in the quotation_requests_controller.rb:
before_action :authenticate_employee!, :only => [:show]
The rspec tests pass. So for some reason Rspec does not register the authentication of the routes.
Here is the output from Rspec for the tests run with the authenticated routes:
QuotationRequestsController
GET index
valid request
renders :index template for signed in employee
assigns quotation requests to template
invalid request
does not render :index template without a signed in employee (FAILED - 1)
GET edit
valid request
renders :edit template with a signed in employee
assigns the requested quotation request to template
invalid request
does not render the :edit template without a signed in employee (FAILED - 2)
PUT update
valid request
valid data
redirects to quotation_request#showtemplate
updates quotation request in the database
invalid data
renders the :edit template
does not update the quotation_request in the database
invalid request
redirects user to the sign in page (FAILED - 3)
GET new
renders :new template
assigns new QuotationRequest to #quotation_request
GET show
invalid request
does not render :show template if an employee or client is not signed in (FAILED - 4)
valid request
renders :show template if an employee or client is signed in
assigns requested quotation_request to #quotation_request
POST create
valid data
redirects to quotation_requests#show
creates new quotation_request in database
invalid data
renders :new template
doesn't creates new quotation_request in database
DELETE destroy
valid request
redirects to the quotation request#index
delets the quotation request from the database
invalid request
does not delete the quotation request without a signed in employee (FAILED - 5)
Failures:
1) QuotationRequestsController GET index invalid request does not render :index template without a signed in employee
Failure/Error: expect(response).to_not render_template(:index)
Didn't expect to render index
# ./spec/controllers/quotation_requests_controller_spec.rb:43:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
2) QuotationRequestsController GET edit invalid request does not render the :edit template without a signed in employee
Failure/Error: expect(response).to_not render_template(:edit)
Didn't expect to render edit
# ./spec/controllers/quotation_requests_controller_spec.rb:92:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
3) QuotationRequestsController PUT update invalid request redirects user to the sign in page
Failure/Error: expect(response).to_not redirect_to(quotation_request)
Didn't expect to redirect to #<QuotationRequest:0x007fe7eb69c8c0>
# ./spec/controllers/quotation_requests_controller_spec.rb:182:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
4) QuotationRequestsController GET show invalid request does not render :show template if an employee or client is not signed in
Failure/Error: expect(response).to_not render_template(:show)
Didn't expect to render show
# ./spec/controllers/quotation_requests_controller_spec.rb:217:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
5) QuotationRequestsController DELETE destroy invalid request does not delete the quotation request without a signed in employee
Failure/Error: expect(QuotationRequest.exists?(quotation_request.id)).to be_truthy
expected: truthy value
got: false
# ./spec/controllers/quotation_requests_controller_spec.rb:361:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
Finished in 2.11 seconds (files took 1.75 seconds to load)
23 examples, 5 failures
Failed examples:
rspec ./spec/controllers/quotation_requests_controller_spec.rb:37 # QuotationRequestsController GET index invalid request does not render :index template without a signed in employee
rspec ./spec/controllers/quotation_requests_controller_spec.rb:83 # QuotationRequestsController GET edit invalid request does not render the :edit template without a signed in employee
rspec ./spec/controllers/quotation_requests_controller_spec.rb:171 # QuotationRequestsController PUT update invalid request redirects user to the sign in page
rspec ./spec/controllers/quotation_requests_controller_spec.rb:208 # QuotationRequestsController GET show invalid request does not render :show template if an employee or client is not signed in
rspec ./spec/cont
Why do the routes I have written not work in Rspec tests?
I take it you are using rspec-rails in your rails app.
Rspec-rails sets up a lot of convenience methods for you, but it also introduces some black-magic, which can lead to some unexpected results - like this.
As you can see here it is explained in the comments for controller specs:
# Supports a simple DSL for specifying behavior of ApplicationController.
# Creates an anonymous subclass of ApplicationController and evals the
# `body` in that context. Also sets up implicit routes for this
# controller, that are separate from those defined in "config/routes.rb".
I guess the logic here is, controller features are different from routing and should be tested separately (and indeed rspec-rails offers a test group for routing), so we do not need the routes for controller specs, meaning you should be able to test your controller without setting up the routes.
In my oppinion, testing the redirect for unauthenticated users is more of an integration test, since it requires multiple parts of your application to work together and as such should not be tested in the controller context, but rather as a feature in some blackbox test.
You can write integration tests by placing them in one of these directories spec/requests, spec/api, and spec/integration or by explicitely declaring their type with
RSpec.describe "Something", type: :request do
or place it in spec/features or declare the type as
RSpec.describe "Something", type: :feature do
depending on which level you want to test the redirect (meaning: only test the request-response cycle, or run it in a simulated browser).
Please refer to the documentation for integration tests on the rspec-rails github page for more information.
I have set up my application so that if the use is logged in, it will skip the welcome page and redirect the user. This is done in the Welcome controller:
def show
if logged_in?
redirect_to myrecipes_url
else
render template: "welcome/home"
end
end
I have written the following tests:
This one fails:
test "login with valid information" do
get login_path
post login_path, session: { email: #user.email, password: 'password' }
assert_redirected_to myrecipes_url
end
And I get the following error:
FAIL["test_login_with_valid_information", UsersLoginTest, 1.4506160049932078]
test_login_with_valid_information#UsersLoginTest (1.45s)
Expected response to be a redirect to <http://www.example.com/myrecipes> but was a redirect to <http://www.example.com/>.
Expected "http://www.example.com/myrecipes" to be === "http://www.example.com/".
This test passes which is a similar test.
test 'welcome page gets skipped when logged in' do
log_in_as(#user)
get root_path
assert_redirected_to myrecipes_url
end
This started occurring when in my controllers (account activation, password reset, sessions) the user should be logged in, I decided to change the line of code: redirect_to myrecipes_url to redirect_to root_url
The reason being that that I wouldn't have to reprogram where the root was redirecting in each controller since that was handled when you routed to the root. However the tests don't seem to be picking up on this.
How do I get the tests to acknowledge the redirect without having to reprogram it into each controller?
I know this question as been answered a lot of times, but I still can't figure what's wrong with my parameters.
I've modified my gmail account so it allows less secured apps, unlocked it with a captcha, but it still considers that my username and password are not accepted, even though i'm sure about them for I checked them 3 times already
Here are my files :
config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:user_name => "mymail#gmail.com",
:password => "mypassword",
:authentication => :login,
:enable_starttls_auto => true
}
config/initializers/smtp_settings.rb
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "mywebsite.fr",
:user_name => "myemail#gmail.com",
:password => 'myPassword',
:authentication => :login,
:enable_starttls_auto => true
}
I guess I've done something wrong, or put something somewhere it doesn't belong, but I've seen so many different ways to do it that I'm lost
Thank you in advance
I am a beginner and this is the first time I am posting on stackoverflow and I hope this helps you out. Please let me know if I can help you further! Also if you want to use sendgrid and heroku I can help with that also.
So when it comes to my gmail authentication settings I also had to allow less secure apps, and unlock the captcha. Along with these two changes in gmail settings, I also had to go to my gmail settings>Forwarding and POP/IMAp> then click ENABLE IMAP. Save your changes. These are all the changes I mad to my gmail.
Make the following changes:
config/initializers/setup_mail.rb
change authentication to :plain
if Rails.env.development? || Rails.env.production?
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
address: 'smtp.gmail.com',
port: '587',
authentication: :plain,
user_name: 'yourEmail#gmail.com',
password: 'yourSecureGmailPassword',
domain: 'mail.google.com',
enable_starttls_auto: true
}
end
config/environments/test.rb host is a website because i am using cloud9
config.action_mailer.default_url_options = { host: 'https://blocipedia-sunnygoo.c9users.io', port: 3000 }
config/environments/development.rb
config.action_mailer.perform_deliveries = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { host: 'same as in test.rb', port: 3000 }
app/models/user.rb
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
default from: "from#example.com"
layout 'mailer'
end
app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
default from: "sunnydgoswami##gmail.com"
def new_user(user)
#user = user
mail(to: user.email, subject: "Welcome to Blocipedia!")
end
end
app/views/layouts/mailer.html.erb
<html>
<body>
<%= yield %>
</body>
</html>
app/views/layouts/mailer.text.erb
<%= yield %>
app/views/user_mailer/new_user.html.erb
'<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-
equiv="Content-Type" />
</head>
<body>
<h1>Welcome, new user!</h1>
<p>
<%= #user.email %>, join us in creating a vibrant wiki
atmosphere!
</p>
<p>
You signed up using <%= #user.email %>. You will be
using this email next time to log in.
</p>
</body>
</html>'
"i have tried everything on stackoverflow but didnot work so i found this solution its the correct way i hope it helps "
To Solve smtplib.SMTPAuthenticationError: Username and Password not accepted Error You need to do Is Just Create App Password and then Use it and you'll be able to use SMTP. Just follow the below step to Create App Password. First of all Login into Your Gmail Account. And then Go To MyAccount Section By visiting https://myaccount.google.com Then Open Security Tab in the Sidebar As Shown in the Image. Then You can see There is Signing in to Google section and Make Sure you have turn on two steps verification if Not Then Turn On two steps verification. When You Turn On Your 2-Step Verification then you'll be able to see App Passwords option. And Now Click on App Passwords. Then select app as Mail and select your corresponding device(if you are on window select window mail).
Then Click on Generate to create App Password. copy the password.
replace your gmail password with this app password in your smtp
Now your app Password is been created. Now Use this password in Your SMTP.
Just Use this Password in SMTP And Now, Your error must be solved. Thank You.
I'm stuck at Chapter 9 in the Rails tutorial - more specifically at the end of section 9.1. My problem is similar to the one in this thread but the solution there didn't work for me.
Here is my user_pages_spec.rb:
require 'spec_helper'
describe "User pages" do
subject { page }
describe "signup page" do
before { visit signup_path }
it { should have_content('Sign up') }
it { should have_title(full_title('Sign up')) }
end
describe "profile page" do
let (:user) {FactoryGirl.create(:user)}
before { visit user_path(user) }
it { should have_content(user.name) }
it { should have_title(user.name) }
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
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_content("Update your profile")}
it { should have_title("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_title(new_name)}
it {should have_selector('div.alert.alert-success')}
it {should have_link('Sign out', href: signout_path)}
specify {expect(user.reload.name).to eq new_name}
specify {expect(user.reload.email).to eq new_email}
end
end
end
Here is the error message:
bundle exec rspec spec/
.............................................FFFFFFFFF
Failures:
1) User pages edit page
Failure/Error: sign_in user
NoMethodError:
undefined method `sign_in' for #<RSpec::Core::ExampleGroup::Nested_4::Nested_4::Nested_1:0x007faa37859d80>
# ./spec/requests/user_pages_spec.rb:49:in `block (3 levels) in <top (required)>'
And here is my spec/support/utilities.rb:
def full_title(page_title)
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
"#{base_title} | #{page_title}"
end
end
def sign_in (user, options={})
if options[:no_capybara]
# Sign in when not using Capybara
remember_token = user.new_remember_token
cookies[:remember_token]
user.update_attribute(:remember_token, User.digest(remember_token))
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
Any suggestions?
I did run bundle install while I was trying to install rcov (Rubymine was complaining about its lack). The installation failed as rcov is not available for my version of rails. That's fine.
The really bizarre thing is that afterwards I re-ran the tests and everything worked. There was no trace of the error message. I am a rails noob but this is a bit rich - a failed bundle install shall not change anything. There was no reason for the error message I observed and now it disappeared without any reason.
==EDIT: I realised the problem is that rails does not seem to empty the cache between tests (which is, in my opinion, a scary bug). By default it fails to re-read the files and thus may ignore changes that have occurred. I put more details here: Rails tutorial: undefined method
I'm stuck (again!) at Chapter 9 (this time in section 9.2.2) of the Rails tutorial. I am getting
bundle exec rspec spec/
................................FFF........................
Failures:
1) Authentication authorization as wrong user submitting a GET request to the Users#edit action
Failure/Error: before {sign_in user, no_capybara: true}
NoMethodError:
undefined method `new_remember_token' for #<User:0x007f8181815448>
# ./spec/support/utilities.rb:13:in `sign_in'
# ./spec/requests/authentication_pages_spec.rb:71:in `block (4 levels) in <top (required)>'
The other 2 errors are of the same type.
Here is spec causing the errors:
describe "as wrong user" do
let(:user) {FactoryGirl.create(:user)}
let(:wrong_user) {FactoryGirl.create(:user, email: "wrong#example.com")}
before {sign_in user, no_capybara: true}
describe "submitting a GET request to the Users#edit action" do
before {get edit_user_path(wrong_user)}
specify { expect(response.body).not_to match(full_title('Edit user'))}
specify { expect(response).to redirect_to(root_url)}
end
describe "submitting a PATCH request to the Users#update action" do
before { patch user_path(wrong_user)}
specify { expect(response).to redirect_to(root_url)}
end
end
And here is the method (utilities.rb) the error message is complaining about:
def sign_in (user, options={})
if options[:no_capybara]
# Sign in when not using Capybara
remember_token = User.new_remember_token
cookies[:remember_token]
user.update_attribute(:remember_token, User.digest(remember_token))
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
The code for the model (User.rb) is here:
class User < ActiveRecord::Base
before_save { self.email = email.downcase}
before_create :create_remember_token
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 }, uniqueness: { case_sensitive: false }
validates :password, length: {minimum: 6}
has_secure_password
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.digest(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.digest(User.new_remember_token)
end
end
I had previously trouble with the sign_in method but it miraculously disappeared. What am I doing wrong?
I finally found the culprit for the erratic test results that I have been observing in this case and, quite likely, on previous occasions (Failure/Error: sign_in user undefined method `sign_in', Rails named route not recognized). The problem seems to be that rails does not clear by default the cache between tests. Which is, actually, downright scary. It seems you cannot really trust the test results. I realised this by commenting out the method that rails was complaining about and re-running the test. The error persisted which meant one thing - rspec was simply working with some cached versions of the files and thus disregarding the changes which I am making. So even if the tests pass you can't be sure that they really do. This is really bizarre. After realising the problem with a bit of googling I found how to force rails to clean the cache - check jaustin's answer here: is Rails.cache purged between tests?