I try to pass this friendship features specs using Capybara, Rspec and FactoryGirls on Rails.
For some reason I can't understand why, I'm always getting failing at this error. Looks like the session is not being destroyed after running a test.
1) Friendships user requests friendship signed in POST /:username/friendships requests friendship
Failure/Error: page.should have_content 'Successfully requested friendship.'
expected there to be text "Successfully requested friendship." in "× You are already signed in. meeter Messages Notifications Settings Settings Logout Explore Dates nearby Suggestions You Messages Notifications Friends Publish Help No ideas found with your criteria."
# ./spec/features/friendships_spec.rb:32:in `block (5 levels) in <top (required)>'
Complete spec
require 'spec_helper'
include Warden::Test::Helpers
Warden.test_mode!
describe "Friendships" do
before(:each) do
#user = FactoryGirl.create(:user, :male)
#friend = FactoryGirl.create(:user, :female)
end
describe "GET /:username/friendships" do
pending "display friendships"
end
context "user requests friendship" do
context "signed in" do
after(:each) do
Warden.test_reset!
end
describe "POST /:username/friendships" do
it "requests friendship" do
login_as(#user, scope: :user)
visit user_path(#friend)
click_button 'Request Friendship'
page.should have_content 'Successfully requested friendship.'
logout(#user)
end
pending "friend receives confirmation notification"
end
describe "POST /:username/friendships/cancels" do
pending "cancels a friendship request sent"
end
end
context "not signed in" do
describe "POST /:username/friendships" do
it "requests friendship" do
visit user_path(#friend)
click_button 'Request Friendship'
page.should have_content 'You need to sign in first to continue.'
end
end
end
end
Any idea how to pass this?
Related
I am testing the avaibility of BusinessArea views in the context of signed in / not signed in user.
At the beginning of the test, I create the business area object (test_ba) thanks to the factory, which returns the object.
I 'puts' the test_ba.id to see it created.
Then I request the tested view.
require 'rails_helper'
RSpec.describe BusinessArea, type: :request do
include Warden::Test::Helpers
describe "Business Areas pages: " do
test_ba = FactoryBot.create(:business_area)
puts test_ba.id
context "when not signed in " do
it "should propose to log in when requesting index" do
get business_areas_path
follow_redirect!
expect(response.body).to include('Sign in')
end
it "should propose to log in when requesting show" do
puts test_ba.id
get business_area_path(test_ba)
follow_redirect!
expect(response.body).to include('Sign in')
end
end
context "when signed in" do
before do
get "/users/sign_in"
test_user = FactoryBot.create(:user)
login_as test_user, scope: :user
end
it "should display index" do
get business_areas_path
expect(response).to render_template(:index)
end
it "should display business area" do
puts test_ba.id
get business_area_path(test_ba)
expect(response).to render_template(:show)
end
end
end
end
The test seems to run correctly, but the last step fails due to missing record!?! The ouput returns:
>rspec spec/requests/business_areas_spec.rb
67
.67
..67
F
Failures:
1) BusinessArea Business Areas pages: when signed in should display business area
Failure/Error: #business_area = BusinessArea.find(params[:id])
ActiveRecord::RecordNotFound:
Couldn't find BusinessArea with 'id'=67
# ./app/controllers/business_areas_controller.rb:159:in `set_business_area'
# ./spec/requests/business_areas_spec.rb:35:in `block (4 levels) in <top (required)>'
Finished in 2.07 seconds (files took 13.05 seconds to load)
4 examples, 1 failure
Failed examples:
rspec ./spec/requests/business_areas_spec.rb:33 # BusinessArea Business Areas pages: when signed in should display business area
Can you help me find what's wrong with this?
RSpec has the let and let! methods that create memoized helpers that you should use to setup your test dependency. let is lazy loading (the block is not evaluated until you reference it) while let! is not.
require 'rails_helper'
RSpec.describe BusinessArea, type: :request do
include Warden::Test::Helpers
describe "Business Areas pages: " do
let!(:test_ba){ FactoryBot.create(:business_area) }
context "when not signed in " do
it "should propose to log in when requesting index" do
get business_areas_path
follow_redirect!
expect(response.body).to include('Sign in')
end
it "should propose to log in when requesting show" do
puts test_ba.id
get business_area_path(test_ba)
follow_redirect!
expect(response.body).to include('Sign in')
end
end
context "when signed in" do
before do
get "/users/sign_in"
test_user = FactoryBot.create(:user)
login_as test_user, scope: :user
end
it "should display index" do
get business_areas_path
expect(response).to render_template(:index)
end
it "should display business area" do
puts test_ba.id
get business_area_path(test_ba)
expect(response).to render_template(:show)
end
end
end
end
But wah! Why doesn't my code work?
In RSpec (and in any good test framework) each example runs in isolation and has its own setup and teardown. This includes rolling back the database or clearing it. RSpec does not even run the tests in consecutive order by design.
The record you are defining in the outer context will not be created for each test run. After the first example when the db is is rolled back its gone.
If you want to set something up for each test use before:
require 'rails_helper'
RSpec.describe BusinessArea, type: :request do
include Warden::Test::Helpers
describe "Business Areas pages: " do
before do
#test_ba = FactoryBot.create(:user)
end
context "when not signed in " do
it "should propose to log in when requesting index" do
get business_areas_path
follow_redirect!
expect(response.body).to include('Sign in')
end
it "should propose to log in when requesting show" do
puts #test_ba.id
get business_area_path(test_ba)
follow_redirect!
expect(response.body).to include('Sign in')
end
end
context "when signed in" do
before do
get "/users/sign_in"
#test_user = FactoryBot.create(:user)
login_as test_user, scope: :user
end
it "should display index" do
get business_areas_path
expect(response).to render_template(:index)
end
it "should display business area" do
puts #test_ba.id
get business_area_path(test_ba)
expect(response).to render_template(:show)
end
end
end
end
But let / let! are preferred for setting up simple dependencies.
I have a test case where after registration devise signup(resource_name, resource) method is called and a redirect_url is sent back to front end , which in turns load the requested page by window.location = redirect_url, though when the next page is hit the next page controller is getting current_user as nil.
Test Case
require 'rails_helper'
feature "sign up with investment profile", js: true do
context 'all fields are valid' do
let(:goal) do
create(
:goal,
risk_level: Tags::BALANCED,
age: 30
)
end
before 'valid sign up steps' do
create(:currency_conversion)
f = File.read("#{Dir.pwd}/spec/response/marketplace/performance.json")
allow(Marketplace::StrategyService).to receive(:get_performance_trail).and_return(JSON.parse(f))
model_portfolio_version = create(:model_portfolio_version, :with_performance_trails)
goal.model_portfolio_version = model_portfolio_version
goal.save!
goal.reload
visit_page_containing_ajax "/suggestions/#{goal.url_hash}"
click_link 'Next: Personal Details'
within('.signup-page-header') do
expect(page).to have_content 'SIGN UP'
end
fill_registration_fields(signup_email)
fill_personal_info_form
wait_for_ajax
find('.btn-primary').click
wait_for_ajax
fill_identification_form
wait_for_ajax
find('.btn-primary').click
wait_for_ajax
fill_declaration_form
wait_for_ajax
find('.btn-primary').click
wait_for_ajax
expect(page).to have_current_path(kyc_dashboard_path(goal.url_hash))
end
context 'User should get registered and redirected to kyc dashboard' do
let(:signup_email) { 'email#example.com' }
context 'user' do
it 'creates investor account' do
expect(page).to have_content('Your registration is successful')
end
end
end
end
end
PS: This is happening in test environment only
After debugging for hours , I found that we are maintaining session in active_record_store when i change it to cookie_store spec works fine.
My rspec test is failing due to the test not matching the correct url path. However, when I check it manually in my browser it works correctly.
My test looks like:
require 'spec_helper'
feature "Photography jobs" do
context "as a user" do
scenario "adds a new photography job" do
user = create(:user)
signin(user.email, user.password)
visit root_path
click_link "Add Job"
fill_in "Name", with: "Joe Blow"
fill_in "Email", with: "joe#hotmail.com"
fill_in "Session Date", with: "9/24/1978"
fill_in "Location", with: "North Shore"
fill_in "Notes", with: "Requested this date."
click_button "Submit"
expect(current_path).to eq job_path
expect(page).to have_content "Session was successfully created."
expect(page).to have_content "North Shore"
expect(page).to have_content "9/24/1978"
end
end
end
The controller looks like:
def new
#job = Job.new
end
def create
#job = Job.new(job_params)
#job.user = current_user
if #job.save
redirect_to #job, notice: 'Session was successfully created.'
else
flash[:error] = #job.errors.full_messages
flash[:errors_list] = #job.errors.messages
redirect_to new_job_path(#job)
end
end
The error when I run rspec spec/features is:
1) Photography jobs as a user adds a new photography job
Failure/Error: expect(current_path).to eq job_path
ActionController::UrlGenerationError:
No route matches {:action=>"show", :controller=>"jobs"} missing required keys: [:id]
# ./spec/features/new_jobs_spec.rb:20:in `block (3 levels) in <top (required)>'
This line is wrong:
expect(current_path).to eq job_path
it must be something like job_path(#job) but since you are creating a new job record with submit so you can't do that test here because the job record doesn't have its :id till it is persisted in your database.
I think it is good to do that kind of test in controller spec but in feature spec.
For feature spec here, just
click_button "Submit"
expect(page).to have_content "Session was successfully created."
expect(page).to have_content "North Shore"
expect(page).to have_content "9/24/1978"
is fine.
Testing filling in the contact form without filling in one of the required fields in one test and then filling in the honey_pot field in another test. The tests when valid info is filled in are passing, but the two other specs are failing.
Update I've been running the test a couple of times and sometimes all the tests pass. Other times, the same specs fail.
Terminal output
3) Pages Home page it should behave like all static pages Footer Contact Form when honeypot is filled does not send an email
Failure/Error: expect(ActionMailer::Base.deliveries).to be_empty
expected empty? to return true, got false
Shared Example Group: "all static pages" called from ./spec/requests/pages_spec.rb:69
# ./spec/requests/pages_spec.rb:46:in `block (6 levels) in <top (required)>'
4) Pages Home page it should behave like all static pages Footer Contact Form when fields are not filled does not send an email
Failure/Error: expect(ActionMailer::Base.deliveries).to be_empty
expected empty? to return true, got false
Shared Example Group: "all static pages" called from ./spec/requests/pages_spec.rb:69
# ./spec/requests/pages_spec.rb:38:in `block (6 levels) in <top (required)>'
pages_spec.rb
require 'spec_helper'
describe "Pages" do
subject { page }
shared_examples_for "all static pages" do |path_name|
before { visit send(path_name) }
describe "Footer" do
describe "Contact Form" do
it { should have_selector('h7', text: 'Contact Us') }
context "when a valid message" do
it "sends an email" do
post contact_create_path, message: attributes_for(:message)
expect(ActionMailer::Base.deliveries.last.to).to eq(["#{ENV["MVP_USERNAME"]}"])
ActionMailer::Base.deliveries.clear
end
end
context "when fields are not filled" do
it "does not send an email" do
post contact_create_path, message: attributes_for(:message, name: '', body: '')
expect(ActionMailer::Base.deliveries).to be_empty
ActionMailer::Base.deliveries.clear
end
end
end
context "when honeypot is filled" do
it "does not send an email" do
post contact_create_path, message: attributes_for(:message, sweet_honey: 'bot')
expect(ActionMailer::Base.deliveries).to be_empty
ActionMailer::Base.deliveries.clear
end
end
end
end
end
describe "Home page" do
before { visit root_path }
it_should_behave_like "all static pages", :root_path
it { should have_text('Quality Cars') }
it { should have_title('Misawa Used Cars - Misawa Auto Sales') }
describe "Send a message" do
before do
fill_in "Name", with: 'name'
fill_in "Email", with: 'email#example.com'
fill_in "Phone", with: '999-9999-9999'
fill_in "Body", with: 'Hello'
click_button "Send"
end
describe "after the message is sent" do
it "should render the desired page with a flash" do
expect(page).to have_text('Quality Cars')
expect(page).to have_title('Misawa Used Cars - Misawa Auto Sales')
expect(page).to have_selector('.alert-box.success')
end
end
end
end
end
I was able to get the specs passing by clearing the ActionMailer::Base.deliveries before and after each of the specs where I tested the deliveries. I also rewrote the tests to make it DRYer using the before(:each) and after(:each) methods describe in Rspec's documentation. Update Even better, around(:each)
Improved Specs
describe "Contact Form" do
it { should have_selector('h7', text: 'Contact Us') }
describe "send a message" do
around(:each) { ActionMailer::Base.deliveries.clear }
context "when a valid message" do
it "sends an email" do
post contact_create_path, message: attributes_for(:message)
expect(ActionMailer::Base.deliveries.last.to).to eq(["#{ENV["MVP_USERNAME"]}"])
end
end
context "when fields are not filled" do
it "does not send an email" do
post contact_create_path, message: attributes_for(:message, name: '', body: '')
expect(ActionMailer::Base.deliveries).to be_empty
end
end
context "when honeypot is filled" do
it "does not send an email" do
post contact_create_path, message: attributes_for(:message, sweet_honey: 'bot')
expect(ActionMailer::Base.deliveries).to be_empty
end
end
end
end
I have a spec for testing a controller as below
require 'spec_helper'
describe ProductsController do
setup :activate_authlogic
describe "user not logged in" do
it "should not GET index" do
get :index
response.should redirect_to(login_path)
end
end
describe "user logged in" do
before(:each) do
UserSession.create :username => "rohit", :password => "test123"
end
it "should GET index" do
get :index
response.should redirect_to(products_path)
end
end
end
I have also used this line in spec_helper.rb
require "authlogic/testcase"
The test for "user not logged in passes" but for "user logged in" fails with
'ProductsController user is logged in should GET index' FAILED
expected redirect to "/products", got no redirect
It seems normal, because You fetch the '/products' url with a logged user. Then He see this page. He is not redirect to the page he see.
Each test are independant. No state are save in previous test.