Capybara::ElementNotFound: Unable to find css "#transaction_form" - ruby-on-rails

I am learning to write feature specs using rspec and capybara. I am trying to write spec for an application, which handles transactions. My transaction controller is as follows:
def new
#transaction = Transaction.new
end
def create
transaction = Transaction.new(transaction_params)
transaction.account = current_account
if transaction.save && transaction.account.save
flash[:success] = 'Transaction successfull'
else
flash[:danger] = 'Insufficient balance'
end
redirect_to root_path
end
It's view is as follows transactions/new:
<div class = 'row'>
<div class = 'col-xs-12'>
<%= form_for(#transaction, id: 'transaction_form', :html => {class: 'form-horizontal', role: 'form'}) do |t| %>
<div class = 'form-group'>
<div class = 'control-label col-sm-2'>
<%= t.label :amount %>
</div>
<div class = 'col-sm-8'>
<%= t.text_field :amount, class: 'form-control', placeholder: 'Enter amount', autofocus: true %>
</div>
</div>
<div class = 'form-group'>
<div class = 'control-label col-sm-2'>
<%= t.label :transaction_type %>
</div>
<div class = 'col-sm-8'>
<%= t.select :transaction_type, Transaction.transaction_types.keys %>
</div>
</div>
<div class = 'form-group'>
<div class = 'col-sm-offset-2 col-sm-10'>
<%= t.submit 'Submit', class: 'btn btn-primary btn' %>
</div>
</div>
<% end %>
I added id: transaction_form to form to avoid ambiguous error.
The spec code is as follows:
RSpec.feature 'Transactions', type: :feature do
context 'create new transaction' do
scenario 'should be successfull' do
visit new_transaction_path
within('#transaction_form') do
fill_in 'Amount', with: '60'
end
click_button 'Submit'
expect(page).to have_content('Transaction successfull')
end
end
end
On running this spec, however,I get error as:
1) Transactions create new transaction should be successfull
Failure/Error:
within('#transaction_form') do
fill_in 'Amount', with: '60'
end
Capybara::ElementNotFound:
Unable to find css "#transaction_form"
What is it I am missing? If I use form directly, it is throwing the ambiguous error as it is getting the same element from different file. What is wrong with this code?
Also, the /transactions/new page will be displayed only if the user is logged in. So will this also affect the transaction spec? If yes, then what should be done?
Please help. Thanks in advance.

If the page you want to interact with is only visible when the user is logged in, then you need to log the user in. That also means you will need to create the user you're going to log in before the test starts. Usually that would be done using either Rails fixtures, or a factory (like the factory_bot gem). Once you have create the user then you'll need to log them in, which can be as simple as visiting the login page and entering the users username and password. If you're using a gem for authentication it may provide a test mode which allows for bypassing actually visiting the login page in order to speed up tests (ie. devise provides this - https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara)

Related

Setting up a simple Rails 5 Mailform

It's been a while since I've programmed in Rails ... getting up to date with all the Rails 5.0 syntax and changes.
Using Rails 5.0.0.1
Using Ruby ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16]
I'm trying to setup a simple contact us form on a landing page. I'm going the route of sending the email direct from the form vs. storing it to the database.
I'm using the mail_form gem and following this thread
I know I'm making some rookie mistakes on my controllers but after following several Stack Q/A's I'm still not quite there.
The model is successfully sending email in Rails Console. I just can't get the controller working. This is a one page site so I'm adding partials to the Index page in the Pages View folder.
Error I'm getting
AbstractController::ActionNotFound (The action 'create' could not be found for PagesController):
Routes
Rails.application.routes.draw do
get 'users/new'
resources :pages
root 'pages#index'
end
Form Partial
app/views/pages/_form.html.erb
<%= form_tag(pages_path) do %>
<div class="row">
<div class="column width-6">
<%= text_field_tag 'firstname', nil, class: 'form-element rounded large', placeholder: 'First Name*', tabindex: '1' %>
</div>
<div class="column width-6">
<%= text_field_tag 'lastname', nil, class: 'form-element rounded large', placeholder: 'Last Name*', tabindex: '2' %>
</div>
<div class="column width-6">
<%= email_field_tag 'email', nil, class: 'form-element rounded large', placeholder: 'Email Address*', tabindex: '3' %>
</div>
<div class="column width-6">
<%= text_field_tag 'website', nil, class: 'form-element rounded large', placeholder: 'Website', tabindex: '4' %>
</div>
<div class="column width-6">
<%= text_field_tag 'phone', nil, class: 'form-element rounded large', placeholder: 'Phone', tabindex: '5' %>
</div>
</div>
<div class="row">
<div class="column width-12">
<%= text_area_tag 'message', nil, class: 'form-element rounded large', placeholder: 'Message*', tabindex: '6' %>
</div>
<div class="column width-12">
<%= submit_tag 'Send Email', class: 'form-submit button rounded medium bkg-theme bkg-hover-green color-white color-hover-white' %>
</div>
</div>
<% end %>
Pages Controller
class PagesController < ApplicationController
def index
#contact = Page.new(params[:page])
if #contact.deliver
redirect_to :back, :notice => "Thank you for contacting us, We'll get back to you shortly!"
else
flash.now[:error] = 'Sorry, it looks like there was an error with your message, Please give us a call or shoot us a text at ....'
end
end
end
Thanks for the help. This community is amazing!
Your routes are missing for the pages controller.
in config/routes.rb add:
resources :pages
in PagesController.rb
class PagesController < ApplicationController
def create
#contact = Page.new(params[:page])
if #contact.deliver
redirect_to :back, :notice => "Thank you for contacting us, We'll get back to you shortly!"
else
flash.now[:error] = 'Sorry, it looks like there was an error with your message, Please give us a call or shoot us a text at ....'
end
end
end
which handles AJAX posts.
redirect_to :back is deprecated in rails 5. Instead there is a new function called redirect_back.
But I wouldn't use the index action for creating a new Page, even if you don't save it to the database. Instead I would define a new action called create and redirect to index in the end. As you already use resources :pages in the routes, you don't need to add anything there. Here you find the default routes and their actions, and what they should be used for: http://edgeguides.rubyonrails.org/routing.html#resource-routing-the-rails-default
Also I would consider using form_for instead of form_tag if you're working with a model. Here you find a simple example: http://edgeguides.rubyonrails.org/getting_started.html#the-first-form
I hope this helped a little :)

How to split full name from view into first_name and last_name and send to model?

I have a form input field in my view where i choose to capture a users name with just one input field:
_signup_form.html.erb
<div class="row">
<%= form_for #user, class: "form", id: "subscribe-form", role: "form" do |u| %>
<div class="line">
<%= u.text_field :name, placeholder: 'Name here...', class: 'form-control', required: true %>
</div>
<div class="line">
<%= u.text_field :email, placeholder: 'Your email here...', class: 'form-control', required: true %>
</div>
<div class="line">
<%= u.submit 'Notify me', class: 'btn btn-danger btn-fill' %>
</div>
<% end %>
</div>
Currently I just save the name variable, which will include both the users first and last name, to the model:
users_controller.rb
def create
#user = User.create(params[:user].permit(:name, :email))
if #user.save
redirect_to user_path(#user), :notice => 'You have been registered'
else
render '/users/new'
end
end
But i'd now like to save not the entire user.name field to the model, but to split it and send user.first_name and user.last_name to the model. I understand how to write the .split methods:
users_helper.rb
def first_name(name)
name.split(' ')[0].capitalize
end
def last_name(name)
name.split(' ')[1].capitalize
end
And i have done my bin/rails g migrate add_first_name_to... and migrated to create the model attributes, but i'm unsure how to integrate #first_name and #last_name methods into the controller to then send each off to the model. A) Can anyone point me in the right direction as to how to do this and B) Is this best practice? (reason I'm only offering name field, as opposed to first_name and last_name fields in the view is as i thought it just represent's a nicer experience for a user to put it in one field, ie no tabbing or cursor click into last_name input). Thanks

Uncheck check_box only not working with rspec / capybara tests

I have a nested form that has 4 checkboxes. Currently, everything is working in browser, but I can't get the capybara tests to uncheck the checkbox and save.
Using Rails 4.2.2 and latest versions of capaybara-webkit and rspec
settings.html.erb
<%= f.fields_for :preferences do |f| %>
<div class="email-notifications-holder">
<div class="email-holder">
<%= f.label :new_match, "Getting a new match each week" %>
<%= f.check_box :new_match, class: "checkbox new_match_email" %>
</div>
<div class="email-holder">
<%= f.label :match_reminder, "New matches Thursday reminder", class: "match_reminder_email" %>
<%= f.check_box :match_reminder, default: true, class: "checkbox" %>
</div>
<div class="email-holder">
<%= f.label :accepted_match, "A Glassbreakers accepted a match", class: "accepted_match_email" %>
<%= f.check_box :accepted_match, default: true, class: "checkbox" %>
</div>
<div class="email-holder">
<%= f.label :new_message, "Received a new message", class: "new_message_email" %>
<%= f.check_box :new_message, default: true, class: "checkbox" %>
</div>
</div>
<% end %>
edit_account_spec.rb
it "allows the user to opt out of new match email", :js do
user = create(:user)
preferences = create(:preference, user: user)
sign_in(user)
visit edit_user_path(user)
click_tab(t("edit_user.tabs.settings"))
find(:css, "#user_preferences_attributes_0_new_match").set(false)
within "#button-container" do
page.find('.save.main-save-button-edit').trigger('click')
end
visit edit_user_path(user)
click_tab(t("edit_user.tabs.settings"))
user.preferences.reload
new_match_email_checkbox = find(".new_match_email")
expect(new_match_email_checkbox.checked?).to be_falsey
end
I've tried clicking it, unchecking it, checking it, trigger clicking it, wrapping it around a within block, reloading the db, etc.
new_match_email_checkbox = find(".new_match_email")
within(".email-notifications-holder") do
page.uncheck('Getting a new match each week')
end
new_match_email_checkbox.set(false)
Right now when you save a user's profile, you must have onboard skills saved or else it will throw an error message when you're trying to click the save button.
part of the user controller
def update
if update_current_user?(user_params)
redirect_to user_path(current_user)
else
flash["notice"] =
"Please choose 3 industries, fields and years of experience."
redirect_to edit_user_path(current_user)
end
end
private
def update_current_user?(update_params)
skills_chosen?(update_params[:user_onboard_skills_attributes]) &&
current_user.update(update_params)
end
Using save_and_open_page, the error alert wasn't appearing so it was unclear what was happening. I was able to debug this by trailing the logs while running the tests using:
tail -f log/test.log
Just using this will uncheck the checkbox
within(".email-notifications-holder") do
page.uncheck('Getting a new match each week')
end
But you then have to grab the element to test it.
new_match_email_checkbox = find(".new_match_email")
expect(new_match_email_checkbox.checked?).to be_falsey
Note:
One thing I am unclear about. Are you trying to make this line work?:
find(:css, "#user_preferences_attributes_0_new_match").set(false)
or are you trying to uncheck the checkbox after you call user.preferences.reload ?

Form not working on Access Denied redirection in Rails 4

I'm working on a Rails 4 web application, using Devise and CanCanCan.
When a user first signs up to create an account, they are redirected to a subscription page where they enter in credit card details, etc.
User Creation -> Subscription Creation = Form works
This is working absolutely perfectly and once they enter in their subscription information, a permission change is made on their account and they can then access a new part of the site. All good.
Now the issue I am having is, if a user signs up, then tries to access this new part of the site without subscribing, I redirect them to the subscription page. However when I do this, the form just doesn't work. They hit submit and nothing happens.
User Creation -> Tries to access resource, gets redirected to
Subscription Creation = Form doesn't work
Here is the code I am using to perform the redirection:
application_controller.rb
def access_denied(exception)
redirect_to(new_subscription_path, alert: exception.message + " Please subscribe.")
end
The strange thing is that I am using the exact same code to redirect when they first create a user account. This is shown here:
registrations_controller.rb
def after_sign_up_path_for(resource)
new_subscription_path
end
Here is the code for the subscription controller:
class SubscriptionsController < ApplicationController
before_filter :authenticate_user!
def new
#subscription = Subscription.new
end
def create
#subscription = Subscription.new(subscription_params)
#user = current_user
#subscription.user_id = current_user.id
if #subscription.save_with_payment
redirect_to success_path, :notice => "Thank you for subscribing!"
if current_user.role = "guest"
User.update(current_user.id, role: "read")
end
UserMailer.subscription_welcome_email(#user).deliver
else
render :new
end
end
def show
#subscription = Subscription.find(params[:id])
end
def destroy
#subscription = Subscription.find_by(user_id: current_user.id)
User.update(current_user.id, role: "guest")
unless #subscription.stripe_customer_id.nil?
customer = Stripe::Customer.retrieve(#subscription.stripe_customer_id)
customer.subscriptions.retrieve(customer.subscriptions.first.id).delete
end
#user = current_user
UserMailer.subscription_destroy_email(#user).deliver
#subscription.destroy
rescue Stripe::StripeError => e
logger.error "Stripe Error: " + e.message
errors.add :base, "Unable to cancel your subscription. #{e.message}."
false
end
def subscription_params
params.require(:subscription).permit(:stripe_card_token, :last_4_digits, :plan, :expiry_month, :expiry_year)
end
end
Form code:
<div class='panel panel-default'>
<div class='panel-heading'>
<h2>Subscribe</h2>
</div>
<div class='panel-body'>
<%= semantic_form_for #subscription, :html => {:class => 'main-form'} do |f| %>
<font color=red><b><%= f.semantic_errors *f.object.errors.keys %></b></font>
<%= f.hidden_field :stripe_card_token %>
<div id='stripe_error' class="alert alert-info" style='display:none'>
</div>
<span class="help-block">Nothing is billed to your card for 7 days. <b>Guaranteed. </b>
<br>If you choose to continue after 7 days, only then will you be billed.</span>
<div class='form-group'>
<%= label_tag :card_number, "Credit Card Number" %><%= image_tag "welcome/checkout/amex.png", alt: "American Express", class: "credit-card-image" %><%= image_tag "welcome/checkout/mastercard.png", alt: "Mastercard", class: "credit-card-image" %><%= image_tag "welcome/checkout/visa.png", alt: "Visa", class: "credit-card-image" %>
<%= text_field_tag :card_number, nil, name: nil, class: 'form-control input-box', :placeholder => 'Credit Card Number' %>
</div>
<div class='row'>
<div class="col-xs-6">
<%= label_tag :card_code, "Security Code on Card (CVC)" %><%= image_tag "welcome/checkout/credit.png", alt: "Credit Card Image", class: "credit-card-image" %>
<%= text_field_tag :card_code, nil, name: nil, class: 'form-control input-box', :placeholder => 'Security Code on Card (CVC)' %>
</div>
<div class="col-xs-6">
<%= label_tag :card_month, "Card Expiration" %><br>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month", class: 'expiration'} %>
<%= select_year nil, {start_year: Date.today.year+1, end_year: Date.today.year+15}, {name: nil, id: "card_year", class: 'expiration'} %>
</div>
</div>
</div>
<div id="stripe_error">
<noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
</div>
<div>
<%= f.submit "Subscribe", class: 'btn standard-button' %>
</div>
<% end %>
</div>
</div>
Can anyone assist? Let me know if any extra code is required. Thanks
EDIT: Just to make things weird, this error is only happening when I hit a link in my navigation that is new_subscription_path .. the access denied works fine if I type in manually the URL of the permissioned resource. Could there be something wrong with the path I am using in the header? Do I need to pass something specific into it? I've also tried to check if it was JavaScript by adding in a console log, but nothing comes through, so I don't think this is an issue, despite it feeling like a JS issue.
You should check you javascript. Clearly it blocks form from submission. I've looked at your previous question here and it looks like your handleStripeResponse handler always goes into else condition block not submitting form as the result. My bet is that $('meta[name="stripe-key"]').attr('content') is undefined after your redirection.
Disabled Turbolinks solved this problem

Rails - Validation across two forms

I have what seems to be a non-standard signup process:
[welcome! enter your email and password] => [cool, enter a lot more information] => [registered]
I'm having trouble getting rails to recognize that I want to validate only the email and password on page 1, and all the other stuff on page 2.
When the user hits the site, they see my welcome page:
class WelcomeController < ApplicationController
def index
#user = User.new
end
end
<%= form_for(#user) do %>
<div class="formItem">
<%= label_tag(:email, "Your email address:") %>
<%= text_field(:user, :email) %>
<br clear="all" />
</div>
<div class="formItem">
<%= label_tag(:password, "Select a password:") %>
<%= password_field_tag(:password) %>
<br clear="all" />
</div>
<%= submit_tag("Sign up today - it's free and easy!", :class => "submitForm") %>
<% end %>
=
class UsersController < ApplicationController
def create
#user = User.new(params[:user])
if #user.save
redirect_to(edit_user_path(#user, :noticeHeader => true ), :notice => 'Please take a minute and answer these additional questions.')
else
render :action => "welcome/index"
end
end
=
Once they click Sign Up, they see my next page of form fields.
The problem I'm running into is that I validates_presence_of fields that are on both pages, in the user model. Since these fields aren't on the welcome page, I get a "undefined local variable or method" error upon submitting the welcome page. For example, I validates_presence_of :title because I want title to be required, but it's only listed on page 2, so page 1 doesn't validate properly.
Thoughts on how to handle this?
Thanks.
Have a look into one of these plugins/gems where you can create Wizard based forms.
http://ruby-toolbox.com/categories/rails_wizards.html my favourite is "ActsAsWizard"

Resources