Rails ActionController::UrlGenerationError - ruby-on-rails

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.

Related

How to factor Capybara rspec testing code?

I need to test a system in which everything is available only after a user is signed in using Devise. Every time I use "it" I have to include the signup code.
Is there a way to factor the code below so that the "let's me make a new post" test and similar tests won't have to include the sign up?
describe "new post process" do
before :all do
#user = FactoryGirl.create(:user)
#post = FactoryGirl.create(:post)
end
it "signs me in" do
visit '/users/sign_in'
within(".new_user") do
fill_in 'Email', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_button 'Log in'
expect(page).to have_content 'Signed in successfully'
end
it "let's me make a new post" do
visit '/users/sign_in'
within(".new_user") do
fill_in 'Email', :with => 'user#example.com'
fill_in 'Password', :with => 'password'
end
click_button 'Log in'
visit '/posts/new'
expect( find(:css, 'select#post_id').value ).to eq('1')
end
end
Your first option is to use the Warden methods provided, as per the documentation on this page:
https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara
Your second option is just to login for real in your tests as you have done in your examples. You can streamline this though by creating some helper methods to do the login work rather than duplicating the code in all of your tests.
To do this, I would create a support directory within your spec directory, and then a macros directory within that. Then create a file spec/support/macros/authentication_macros.rb:
module AuthenticationMacros
def login_as(user)
visit '/users/sign_in'
within('.new_user') do
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
end
click_button 'Log in'
end
end
Next, update your RSpec config to load your macros. In either spec_helper.rb or rails_helper.rb if you're using a newer setup:
# Load your support files
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Include the functions defined in your modules so RSpec can access them
RSpec.configure do |config|
config.include(AuthenticationMacros)
end
Finally, update your tests to use your login_as function:
describe "new post process" do
before :each do
#user = FactoryGirl.create(:user)
#post = FactoryGirl.create(:post)
login_as #user
end
it "signs me in" do
expect(page).to have_content 'Signed in successfully'
end
it "let's me make a new post" do
expect( find(:css, 'select#post_id').value ).to eq('1')
end
end
Obviously, make sure you have password defined in your user factory.

Creating multiple FactoryGirl records. Validation failed: Email has already been taken

I'm writing the RSpec tests for the index action for Project. A project belongs_to a client, which belongs_to a user.
What I'm trying to do is create 30 instances of project to be used in pagination. All belonging to the same user.
When I run the tests, I'm giving the following error (I've tried rake db test:prepare):
Failure/Error: before(:all) { #projects = FactoryGirl.create_list(:project, 30, user: user) }
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
factories.rb
FactoryGirl.define do
factory :user do
name "John Nana"
email "john#nana.com"
password "woopwoop1"
password_confirmation "woopwoop1"
end
factory :client do
name "Widget inc."
user
end
factory :user1 do
name "Bob Inc"
email "lol#catz.com"
password "nayy1"
password_confirmation "nayy1"
end
factory :project do
sequence(:name) { |n| "Project #{n}" }
fee "250"
client
end
end
project_pages_spec.rb
require 'spec_helper'
describe "create" do
let(:user) { FactoryGirl.create(:user) }
let(:submit) { "Create project" }
describe "when signed in" do
before do
capybara_sign_in(user)
#client = user.clients.create(name: "Widget inc.")
visit new_project_path
end
describe "with valid information" do
describe "from /projects" do
before do
visit projects_path
click_link "Add project"
fill_in "Project name", with: "Brochure"
fill_in "Fee", with: "1000"
select(#client.name, from: 'project_client_id')
end
it "should create a project and redirect to /projects" do
expect { click_button submit }.to change(Project, :count).by(1)
current_path.should == '/projects'
end
end
before do
fill_in "Project name", with: "Brochure"
fill_in "Fee", with: "1000"
select(#client.name, from: 'project_client_id')
end
it "should create a project" do
expect { click_button submit }.to change(Project, :count).by(1)
end
end
describe "with invalid information" do
before do
too_long_project = "a" * 50
fill_in "Project name", with: too_long_project
fill_in "Fee", with: "1000000000"
select(#client.name, from: 'project_client_id')
end
it "should not create a project" do
expect { click_button submit }.not_to change(Project, :count)
end
end
end
describe "when not signed in" do
before { visit new_project_path(user) }
it "should redirect to signin path" do
current_path.should == '/signin'
end
end
end
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before do
capybara_sign_in(user)
visit projects_path
end
describe "pagination" do
before(:all) { #projects = FactoryGirl.create_list(:project, 30, user: user) }
after(:all) { Project.delete_all }
it { should have_selector('div.pagination') }
it "should list each user" do
Project.paginate(page: 1).each do |project|
expect(page).to have_selector('li', text: project.name)
end
end
it "should list all projects" do
#projects.each do |p|
expect(page).to have_selector('li', p.name)
end
end
end
end
You can use FactoryGirl's Sequences to generate unique email addresses:
factory :user do
name "John Nana"
sequence(:email) { |n| "person#{n}#example.com" }
password "woopwoop1"
password_confirmation "woopwoop1"
end

Rspec. Delete action doesn't work with let()

I have Rspec testing controller actions via visiting pages.
And when I'm declaring new object through let() for create and edit actions - it's all fine. But for delete it doesn't work and I have to declare instance variable to make it pass.
My goal is to get rid of instance variable declaration in delete action.
It stops me from finishing re-factoring and I want to know why this happen?
Maybe it's somehow related to Capybara scope.
Failed tests looks like:
Failure/Error: it {should have_content('delete')}
expected #has_content?("delete") to return true, got false
and
Failure/Error: expect{click_link('delete')}.to change(Crew, :count).by(-1)
Capybara::ElementNotFound:
Unable to find link "delete"
My whole test
require 'spec_helper'
describe 'CrewPage' do
subject {page}
let(:user) {FactoryGirl.create(:user)}
let(:crew) {Crew.create(name: name, secondname: secondname, rate: rate)}
let(:name) {'Name'}
let(:secondname) {'First'}
let(:rate) {1000}
before {sign_in(user)}
#==============================New page===========>>
describe 'new crew member page' do
before {visit new_crew_path}
it {should have_title('New member')}
let(:submit) {"Create"}
context 'invalid creation' do
it 'should not create crew member' do
expect{click_button submit}.not_to change(Crew, :count)
end
end
context 'valid crew member creation' do
before do
fill_in 'Name', with: name
fill_in 'Secondname', with: secondname
fill_in 'Rate', with: rate
end
it 'should create crew member' do
expect{click_button submit}.to change(Crew, :count).by(1)
end
end
end
#==============================Show page===========>>
describe 'show page' do
before {visit crew_path(crew)}
it {should have_title("#{crew.combine_names} profile")}
end
#==============================Edit page===========>>
describe 'edit page' do
let(:reload_n) {name*2}
let(:reload_sn) {secondname*2}
let(:reload_r) {rate*2}
before {visit edit_crew_path(crew)}
it {should have_title('Edit panel')}
context 'successfull edit' do
before do
fill_in 'Name', with: reload_n
fill_in 'Secondname', with: reload_sn
fill_in 'Rate', with: reload_r
click_button('Save')
end
it {should have_content(reload_n)}
it {should have_content(reload_sn)}
it {should have_content(reload_r)}
end
end
#==============================Delete action===========>>
describe 'delete action from index page' do
before do
#crew = Crew.create(name: name, secondname: secondname, rate: rate)
visit root_path
end
it {should have_content('delete')}
it 'should delete crew member' do
expect{click_link('delete')}.to change(Crew, :count).by(-1)
end
end
end
let block is not executed unless it is called in the test itself. Because you are not using this variable prior to visit_page, crew model is not created and hence it is not displayed on the page capybara is playing with. If you want it to execute before each test, you have to call let! instead:
let!(:crew) { Crew.create(name: name, secondname: secondname, rate: rate)}

Keeping user in the database between tests using Capybara?

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.

syntax error, unexpected tIDENTIFIER, expecting keyword_end

What am I doing wrong? I think all my ends are right. I am getting this error for
describe "visiting the edit page" do
describe "submitting to the update action" do
describe "visiting the user index" do
describe "as wrong user" do
FactoryGirl.create(:user, email: "wrong#example.com")}
and
describe "visiting Users#edit page" do
This is the error I am getting when I run rspec
syntax error, unexpected tIDENTIFIER, expecting keyword_end
describe "authorization" do
describe "for non-signed-in users" do
let(:user) {FactoryGirl.create(:user)}
describe "when attempting to visit a protected page" do
before do
visit edit_user_path(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
describe "after signing in" do
it "should render the desired protected page" do
page.should have_selector('title', text: 'Edit user')
end
describe "when signing in again" do
before do
click_link "Sign out"
click_link "Sign in"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
it "should render the default (profile) do
page.should have_selector('title', text: user.name)
end
end
end
end
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') }
it {should have_selector('div.alert.alert-notice')}
end
describe "submitting to the update action" do
before { put user_path(user)}
specify {response.should redirect_to(signin_path)}
end
describe "visiting the user index" do
before {visit users_path}
it {should have_selector{'title', text: 'Sign in'}}
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: '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
You are missing a " at the end of it "should render the default (profile) do.
Right off the bat
it "should render the default (profile) do
Is missing the end quote and be should be
it "should render the default (profile)" do
I had in the podspec this character ” instead of this ".

Resources