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.
Related
I have basic rspec tests for my Client model. And it broke after I assigned it to current_user. I have problems figuring out what's wrong. Looking for some help.
Problem exist with show, edit and delete actions
require 'spec_helper'
describe 'ClientPage' do
subject {page}
let(:user) {FactoryGirl.create(:user)}
let(:client) {user.clients.build(client_name: client_name, client_secondname: client_secondname,
budget: budget, project: project)}
let(:client_name) {'Client'}
let(:client_secondname) {'First'}
let(:budget) {3000}
let(:project) {'Project'}
before {sign_in(user)}
#==============================New page===========>>
describe 'new client page' do
before {visit new_client_path}
it {should have_title('New client')}
let(:submit) {"Create"}
describe 'create' do
context 'invalid creation' do
it 'should not create client' do
expect{click_button submit}.not_to change(Client, :count)
end
end
context 'valid client creation' do
before do
fill_in 'Client name', with: client_name
fill_in 'Client secondname', with: client_secondname
fill_in 'Budget', with: budget
fill_in 'Project', with: project
end
it 'should create client' do
expect{click_button submit}.to change(Client, :count).by(1)
end
end
end
end
#==============================Show page===========>>
describe 'show' do
before {visit client_path(client)}
it {should have_title("#{client.combine_names} profile")}
end
#==============================Edit page===========>>
describe 'edit' do
let(:reload_cn) {client_name*2}
let(:reload_csn) {client_secondname*2}
let(:reload_bgt) {client.budget*2}
let(:reload_prg) {client.project*2}
before {visit edit_client_path(client)}
it {should have_title('Edit client panel')}
context 'successfull edit' do
before do
fill_in 'Client name', with: reload_cn
fill_in 'Client secondname', with: reload_csn
fill_in 'Budget', with: reload_bgt
fill_in 'Project', with: reload_prg
click_button('Save')
end
it {should have_content(reload_cn)}
it {should have_content(reload_csn)}
it {should have_content(reload_bgt)}
it {should have_content(reload_prg)}
end
end
#==============================Delete action===========>>
describe 'delete' do
before do
#client = user.clients.build(client_name: client_name, client_secondname: client_secondname, budget: budget, project: project)
visit root_path
end
it 'should delete client' do
expect{#client.delete}.to change(Client, :count).by(-1)
end
end
end
Solved. I've missed one thing - build do not save to database so example won't have an id.
create or FactoryGirl hepls.
My issue is that I have to create a new user and login for each individual capybara test.
An example is below:
require 'spec_helper'
describe "users" do
describe "user registration" do
it "should create a new user and log in" do
# Register a new user to be used during the testing process
visit signup_path
fill_in 'Email', with: 'testuser'
fill_in 'Password', with: 'testpass'
fill_in 'Password confirmation', with: 'testpass'
click_button 'Create User'
current_path.should == root_path
page.should have_content 'Thank you for signing up!'
end
end
describe "user login" do
it "should log in" do
# log in
visit login_path
fill_in 'Email', with: 'testuser'
fill_in 'Password', with: 'testpass'
click_button 'Log In'
current_path.should == root_path
page.should have_content 'Logged in!'
end
end
end
The login test fails because the user no longer exists in the database for that test.
This could be fixed simply by putting both in one test, but I believe that is bad practice.
Also I have another file which currently is registering and logging in between each test using a before_do, which also seems to be quite bad... you can see that code here.
For the record this is my first rails app so perhaps I am trying to do this the wrong way. I would like to dry it up as much as possible..
Is capybara really this bad to use on pages that require user login?
I have done it this way.
require "spec_helper"
describe "Users" do
subject { page }
describe "User Registration" do
before { visit signup_path }
let(:submit) { "Sign up" }
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 "Email", with: "user#example.com"
fill_in "Password", with: "foobar12"
fill_in "Password confirmation", with: "foobar12"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after registration" do
before { click_button submit }
it { should have_content 'Thank you for signing up!' }
end
describe "after registration signout and login" do
let(:user) { User.find_by_email('user#example.com') }
before do
click_button submit
visit signout_path
sign_in user # sign_in is a method which u can define in your spec/support/utilities.rb . Define once and use at multiple places.
end
it { should have_content 'Logged In!' }
it { should have_link('Logout') }
end
end
end
end
# spec/support/utilities.rb
def sign_in(user)
visit sign_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
end
your every describe and it block will run after the before block in parent that's why we need to click_button in every block in above test cases.
With rspec, it's quite clear how you should organise your unit specs. The directory structure inside spec is very similar to that found in the app directory, so model specs go in the model directory, controller specs go in the controller directory and so on.
But it's not so clear with integration testing. I have just one file pertaining to integration testing: spec/features/integration.rb
Is the idea to create one elaborate spec that tests every faculty of your application? Something like this:
require 'spec_helper'
describe "Everything", js: true do
before do
#user_0 = FactoryGirl.build(:user_0)
#user_1 = FactoryGirl.build(:user_1)
#user_2 = FactoryGirl.build(:user_2)
#user_3 = FactoryGirl.build(:user_3)
end
it "can create a user" do
visit root_path
click_link 'Sign In'
ap #user_0
fill_in('Email', with: #user_0.email)
fill_in('Password', with: #user_0.password)
click_button 'Sign in'
visit('/user_friendships')
end
it "can create a user" do
end
it "can create a user" do
end
it "can create a user" do
end
it "GET /root_path" do
visit root_path
page.should have_content("All of our statuses")
click_link "Post a New Status"
page.should have_content("New status")
fill_in "status_content", with: "Oh my god I am going insaaaaaaaaane!!!"
click_button "Create Status"
page.should have_content("Status was successfully created.")
click_link "Statuses"
page.should have_content("All of our statuses")
page.should have_content("Jimmy balooney")
page.should have_content("Oh my god I am going insaaaaaaaaane!!! ")
end
end
But a lot longer?
Should I use more than one file? How should I use the describe blocks? I'm only using one at the moment and that doesn't feel right.
The short answer is: No, it's not meant to go into one file.
Bigger projects split their acceptance test-suite into files based on feature sets. If you have a lot of tests, they are often split up into different directories. The way that you organize those tests is up to you. I have seen a lot of different approaches here. I tend to group spec with similar requirements on database setup, aka test-data.
If you want to have great guide for your rspec tests, go and have a look at this site: http://betterspecs.org/
It's usually desirable to split integration tests per page or flow in your application.
For example, you could try:
# spec/users/sign_in_spec.rb
RSpec.describe 'Users Sign In', js: true do
let!(:user) { FactoryGirl.build(:user_0) }
it "can sign in" do
visit root_path
click_link 'Sign In'
fill_in('Email', with: user.email)
fill_in('Password', with: user.password)
click_button 'Sign in'
page.should have_content('Signed In')
end
end
# spec/statuses/manage_status.rb
RSpec.describe 'Statuses', js: true do
it "should be able to post a status" do
visit root_path
page.should have_content("All of our statuses")
click_link "Post a New Status"
fill_in "status_content", with: "Everything is Alright"
click_button "Create Status"
page.should have_content("Status was successfully created.")
click_link "Statuses"
page.should have_content("All of our statuses")
page.should have_content("Everything is Alright ")
end
end
If you are looking for a way to organize your specs, you could use Capybara Test Helpers to encapsulate the code and make the tests more readable. For example:
# spec/users/sign_in_spec.rb
RSpec.describe 'Users Sign In', js: true, test_helpers: [:login] do
let!(:user) { FactoryGirl.build(:user_0) }
it "can sign in" do
visit root_path
login.enter_credentials(email: user.email, password: user.password)
current_page.should.have_content('Signed In')
end
end
# spec/statuses/manage_status.rb
RSpec.describe 'Statuses', js: true, test_helpers: [:statuses] do
it "should be able to post a status" do
visit root_path
current_page.should.have_content('All of our statuses')
statuses.post('Everything is Alright')
statuses.should_now.have_status('Everything is Alright')
end
end
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?
I am trying to run this test but for some reason its failing.
describe "User Pages" do
subject { page }
.
.
describe "Sign up" do
before { visit signup_path }
let(:submit) { "Sign Me Up" }
.
.
describe "with valid information" do
before do
fill_in "name", with: "newuser"
fill_in "Username", with: "user254"
fill_in "Email", with: "user#yahoo.com"
select "Male", from: "gender"
fill_in "Password", with: "password"
fill_in "Confirm Password", with: "password"
end
it "Should create a user" do
expect { click_button submit}.to change(User, :count).by(1)
end
end
However, when I run the test I get this error
Failures:
1) User Pages signup with valid information Should create a user
Failure/Error: expect { click_button submit}.to change(User, :count).by(1)
count should have been changed by 1, but was changed by 0
# ./spec/requests/user_pages_spec.rb:35:in `block (4 levels) in <top (required)>'
Finished in 4.61 seconds
35 examples, 1 failure
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:34 # User Pages signup with valid information Should create a user
This is my create action in my controller
def create
#user = User.new(params[:user])
if #user.save
redirect_to #user
else
render 'new'
end
end
When I try signing up in the browser, signup is successfull. Is anything wrong with my test? Thanks
check if the user is being saved on the controller:
def create
#user = User.new(params[:user])
puts "valid? = #{#user.valid?.inspect}"
if #user.save
puts 'saved!'
redirect_to #user
else
puts 'not saved'
puts #user.errors.inspect
render 'new'
end
end
that will print the controller process and you will know what's happening
if nothing gets printed, then the problem is some before_filter that's preventing the create action to being called
try it with
it "Should create a user" do
click_button submit
User.count.should == 1
end