Capybara: Unable to find form field with js: true - ruby-on-rails-3

I wrote some tests using capybara for request testing using poltergeist and phantomjs as javascript driver.
The following steps for filling in a login form works great without js:
it "signs in" do
visit new_user_session_path
fill_in "Email", with: user
fill_in "Password", with: password||"foobar"
click_button "Login"
end
If I define my test with js it "signs in", js: true do my test fails with error:
Capybara::ElementNotFound: Unable to find field "Email"
The login form itself is built using simple_form as form generator and bootstrap in frontend.
The fields do not have a label. the search text is only contained in the placeholder attribute.
= simple_form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f|
= f.input :email, :placeholder => User.human_attribute_name(:email), :label => false, :input_html => {:class => 'input-xlarge'}
= f.input :password, :placeholder => User.human_attribute_name(:password), :label => false, :input_html => {:class => 'input-xlarge'}
%div
= f.button :submit, "Login", :class => 'btn btn-large btn-primary'
This code generates the following html code
<form accept-charset="UTF-8" action="/users/login" class="simple_form new_user" id="new_user" method="post" novalidate="novalidate">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓">
</div>
<div class="control-group email required user_email">
<div class="controls">
<input class="string email required input-xlarge" id="user_email" name="user[email]" placeholder="Email" size="50" type="email" value="">
</div>
</div>
<div class="control-group password required user_password">
<div class="controls">
<input class="password required input-xlarge" id="user_password" name="user[password]" placeholder="Password" size="50" type="password">
</div>
</div>
<div>
<input class="btn btn btn-large btn-primary" name="commit" type="submit" value="Login">
</div>
</form>
Do you have any Idea how to ensure that the fields are found even if js is activated?

I don't know how your Webrat test passed. In my experience Capybara can't find "Email" if there is no matching Label or id.
In your case, since you don't use label, I suggest you to find the field with id
fill_in "user_email", with user.email
# user_email is the id created by simple_form in general case. Verify yours.
# Don't need "#" before id.

Take a screenshot after visit new_user_session_path and verify html is being rendered when :js => true.
visit new_user_session_path
save_and_open_page
If nothing is being rendered, just an empty html document, make sure in your spec_helper.rb
config.use_transactional_fixtures = false
Also try using DatabaseCleaner gem.
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with :truncation
end
config.before(:each) do
if example.metadata[:js]
DatabaseCleaner.strategy = :truncation
else
DatabaseCleaner.strategy = :transaction
end
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end

Related

Wicked_PDF does not download when I switch to using form_with instead of form_tag

I noticed a bug with my view where my form could not be submitted after the initial submission to generate a PDF, and during research saw that form_with was the recommended way to build forms going forward with rails. I updated my form, and everything seems to be working the way it's supposed to, but now the PDF doesn't download as before and just seems to render the string in a response without generating the file. Using Wicked-PDF and Rails 5.2.1. Sorry if I'm missing something super obvious!
Using form_tag (pdf downloads as expected):
form in view:
<%= form_tag("download_pdf", format: :pdf, method: "get") do %>
<div class="input-group mb-3">
<%= collection_select(:location, :id, Location.all, :id, :name, {:include_blank => 'Filter by location'}, {:id => 'qr_code_loc_select', :selected_value => '', :name => 'location', :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= collection_select(:name, :id, DeviceType.all, :id, :name, {:include_blank => 'Filter by device type'}, {:id => 'qr_device_type_select', :selected_value => '', :name => "device_type", :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<input type="number" name="width" class="form-control label_size_input" id="label_width" step="0.001" placeholder="Label Width" autocomplete ='off' aria-describedby="basic-addon3">
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<div class="input-group mb-3">
<input type="number" name="height" class="form-control label_size_input" id="label_height" step="0.001" placeholder="Label Height" autocomplete ='off' aria-describedby="basic-addon3">
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<%= label_tag "qr_col", "Columns:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= select_tag "qr_col", options_for_select(["1","2", "3", "4", "5"], "3"), {:autocomplete => 'off'}%>
</div>
<%= label_tag "paper_size", "Paper Size:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= select_tag "paper_size", options_for_select(#paper_size, "A4"), {:autocomplete => 'off'}%>
</div>
<div class="btn-group mb-3" role="group" aria-label="pdf_export_button" id="pdf_export">
<%= hidden_field_tag :column_number %>
<%= hidden_field_tag :label_size %>
<%= hidden_field_tag :format, "pdf" %>
<%= submit_tag("Create PDF Document", {:class=> "btn btn-secondary"}) %>
<% end %>
</div>
in controller:
def download_pdf
#columns = params[:column_number].to_i
#height = params[:height]
#width = params[:width]
#paper_size = params[:paper_size]
#type = params[:device_type]
#location = params[:location]
if #type.blank?
if #location.blank?
#devices = Device.all
else
#devices = get_devices_by_location(#location)
end
else
if #location.blank?
#devices = Device.where('device_type_id=?', #type)
else
#devices = get_devices_by_type_and_location(#type, #location)
end
end
pdf_string = render_to_string(
template: "qr_codes/show.html.erb",
layout: "layouts/pdf_layout.pdf.erb",
viewport_size: '1280x1024',
page_size: #paper_size
)
respond_to do |format|
format.pdf do
pdf = WickedPdf.new.pdf_from_string(pdf_string)
send_data pdf, :filename => "report.pdf", :type => "application/pdf"
end
end
end
in console:
Started GET "/qr_codes/download_pdf?utf8=%E2%9C%93&location=&device_type=&width=&height=&qr_col=3&paper_size=A4&column_number=3&label_size=&format=pdf&commit=Create+PDF+Document" for 127.0.0.1 at 2018-11-14 20:03:51 -0500
Processing by QrCodesController#download_pdf as PDF
Parameters: {"utf8"=>"✓", "location"=>"", "device_type"=>"", "width"=>"", "height"=>"", "qr_col"=>"3", "paper_size"=>"A4", "column_number"=>"3", "label_size"=>"", "commit"=>"Create PDF Document"}
Rendering qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb
(0.4ms) SELECT COUNT(*) FROM "devices"
Device Load (0.6ms) SELECT "devices".* FROM "devices"
Rendered qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb (778.0ms)
"***************[\"/Users/joe/.rbenv/versions/2.5.0/bin/wkhtmltopdf\", \"-q\", \"file:////var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf20181114-912-1opkhpt.html\", \"/var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf_generated_file20181114-912-m57i12.pdf\"]***************"
Rendering text template
Rendered text template (0.1ms)
Sent data report.pdf (1.7ms)
Completed 200 OK in 3077ms (Views: 1.2ms | ActiveRecord: 1.0ms)
Using form_with (pdf does not generate as expected and only has an unformatted string in response):
form in view:
<%= form_with url: download_pdf_path(format: :pdf), method: "get" do |f| %>
<div class="input-group mb-3">
<%= f.collection_select(:id, Location.all, :id, :name, {:include_blank => 'Filter by location'}, {:id => 'qr_code_loc_select', :selected_value => '', :name => 'location', :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= f.collection_select(:id, DeviceType.all, :id, :name, {:include_blank => 'Filter by device type'}, {:id => 'qr_device_type_select', :selected_value => '', :name => "device_type", :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= f.number_field nil, {:name => "width", :id => "label_width", :class => "form-control label_size_input", :step => "0.001", :placeholder => "Label Width", :autocomplete => 'off'} %>
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<div class="input-group mb-3">
<%= f.number_field nil, {:name => "height", :id => "label_height", :class => "form-control label_size_input", :step => "0.001", :placeholder => "Label Height", :autocomplete => 'off'} %>
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<%= label_tag "qr_col", "Columns:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= f.select "column_number", options_for_select(["1","2", "3", "4", "5"], "3"), {:autocomplete => 'off'}, :id => "qr_col"%>
</div>
<%= label_tag "paper_size", "Paper Size:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= f.select "paper_size", options_for_select(#paper_size, "A4"), {:autocomplete => 'off'}%>
</div>
<div class="btn-group mb-3" role="group" aria-label="pdf_export_button" id="pdf_export">
<%= f.hidden_field :label_size %>
<%= f.submit("Create PDF Document", {:class=> "btn btn-secondary", :data => { turbolinks: false }}) %>
</div>
<% end %>
controller:
def download_pdf
#columns = params[:column_number].to_i
#height = params[:height]
#width = params[:width]
#paper_size = params[:paper_size]
#type = params[:device_type]
#location = params[:location]
if #type.blank?
if #location.blank?
#devices = Device.all
else
#devices = get_devices_by_location(#location)
end
else
if #location.blank?
#devices = Device.where('device_type_id=?', #type)
else
#devices = get_devices_by_type_and_location(#type, #location)
end
end
respond_to do |format|
format.pdf do
pdf = WickedPdf.new.pdf_from_string(
render_to_string(
template: 'qr_codes/show.html.erb',
layout: 'layouts/pdf_layout.pdf.erb',
page_size: #paper_size
),
)
send_data pdf, :filename =>'PDF Report-' + Time.now.strftime('%v %H:%M:%S').to_s, disposition: 'attachment', :type => "application/pdf"
end
end
end
in console:
Started GET "/qr_codes/download_pdf_path?utf8=%E2%9C%93&location=&device_type=&width=&height=&column_number=3&paper_size=A4&label_size=&format=pdf&commit=Create%20PDF%20Document" for 127.0.0.1 at 2018-11-14 20:01:04 -0500
Processing by QrCodesController#download_pdf as PDF
Parameters: {"utf8"=>"✓", "location"=>"", "device_type"=>"", "width"=>"", "height"=>"", "column_number"=>"3", "paper_size"=>"A4", "label_size"=>"", "commit"=>"Create PDF Document"}
Rendering qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb
(0.3ms) SELECT COUNT(*) FROM "devices"
Device Load (1.2ms) SELECT "devices".* FROM "devices"
Rendered qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb (453.5ms)
"***************[\"/Users/joe/.rbenv/versions/2.5.0/bin/wkhtmltopdf\", \"-q\", \"file:////var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf20181114-912-1ym4a9q.html\", \"/var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf_generated_file20181114-912-edkha0.pdf\"]***************"
Rendering text template
Rendered text template (0.1ms)
Sent data PDF Report-14-NOV-2018 20:01:07 (1.6ms)
Completed 200 OK in 2682ms (Views: 1.1ms | ActiveRecord: 1.5ms)
IT WAS SOMETHING DUMB--decided to turn my attention to the form_with documentation and found out that remote: true is set by default. If you set this to local: true, the issue is resolved. Hope that helps someone else!

Twitter Integration using Ruby on Rails

I have a Ruby on Rails application (Ruby-1.9, Rails-3.2)which integrates with twitter to display the latest tweets containing a particular "keyword" dynamically. But it throws an error as NameError in TweetsController#create uninitialized constant Twitter::Search on the browser .
I have run the db migrations, restarted the server and tried for various options available on the net. But nothing seems to work. Can anyone help to resolve this error ?
The model and controller files are below
Tweet.rb (model file)
class Tweet < ActiveRecord::Base
def self.get_latest_new_year_resolution_tweets(keyword)
search = Twitter::Search.new
search.containing(keyword).result_type("recent").per_page(100).fetch.each do |tweet_results|
twitter_created_at = DateTime.parse(tweet_results.created_at)
unless Tweet.exists?(['twitter_created_at = ? AND from_user_id_str = ?', DateTime.parse(tweet_results.created_at), tweet_results.from_user_id_str])
Tweet.create!({
:from_user => tweet_results.from_user,
:from_user_id_str => tweet_results.from_user_id_str,
:profile_image_url => tweet_results.profile_image_url,
:text => tweet_results.text,
:twitter_created_at => twitter_created_at
})
end
end
end
end
TweetsController
class TweetsController < ApplicationController
def index
end
def create
String strText = params[:tweet][:search].to_s
Tweet.get_latest_new_year_resolution_tweets(strText)
if Tweet.count > 0
Tweet.delete_all
end
Tweet.get_latest_new_year_resolution_tweets(strText)
#tweets = Tweet.order("twitter_created_at desc")
render 'index'
end
end
Index.html.erb (The view file)
<h1>Twitter connect</h1>
<form action="create" method="post">
<label for="keyword">Enter Keyword</label>
<input id="keyword" name="tweet[search]" size="30" type="text" />
<input type="submit" value="search" />
</br> <br>
</form>
</br></br>
<div id="container">
<% if (#tweets != nil && #tweets.count>0) then %>
<ul>
<% #tweets.each do |tweet| %>
<li class="<%=cycle('odd', '')%>">
<%= link_to tweet.from_user, "http://twitter.com/#{tweet.from_user}", :class => "username", :target => "_blank" %>
<div class="tweet_text_area">
<div class="tweet_text">
<%=raw display_content_with_links(tweet.text) %>
</div>
<div class="tweet_created_at">
<%= time_ago_in_words tweet.twitter_created_at %> ago
</div>
</div>
</li>
<% end %>
</ul>
<% end %>
</div>
The gemfile is as below
source 'http://rubygems.org'
gem 'rails', '3.0.3'
gem 'sqlite3', '1.3.6',:group => :development
#gem 'ruby-mysql'
#gem 'mysql2'
group :production do
gem 'pg'
end
gem 'twitter', '4.6.2'
Include below code in your application.rb or top of app/models/tweet.rb files
require 'twitter'
Ex:-
class Tweet < ActiveRecord::Base
require 'twitter'
....
...
end

Simple form label class

I want to use simple-form and bootstrap to generate a horizontal form with 2 rows. The first row should have two inputs side by side - one for first name with one label and the second row should have an input for email. My problem is that that label for the first row is not getting the control-label class that is required for the horizontal form to render correctly. However, all the proper classes are being applied to the email field.
Below is my code:
= simple_form_for #order, :url => '/product/process_order', :html => {:class => 'form-horizontal'} do |f|
.form-inputs
.control-group
= f.label :first, "Full and last name"
.controls
= f.input_field :first, :class => "span2", :placeholder => 'First'
= f.input_field :last, :class => "span3" , :placeholder => 'Last'
= f.input :email, :placeholder => 'you#example.com'
Which generates:
<form accept-charset="UTF-8" action="/product/process_order" class="simple_form form-horizontal" id="new_order" method="post" novalidate="novalidate">
<div class="form-inputs">
<div class="control-group">
<label for="order_first">Full and last name</label>
<div class="controls">
<input class="string required span2" id="order_first" name="order[first]" placeholder="First" size="50" type="text">
<input class="string required span3" id="order_last" name="order[last]" placeholder="Last" size="50" type="text">
</div>
</div>
<div class="control-group email required">
<label class="email required control-label" for="order_email">
<abbr title="required">*</abbr> Email
</label>
<div class="controls"><input class="string email required" id="order_email" name="order[email]" placeholder="you#example.com" size="50" type="email"></div>
</div>
</div>
</form>
In your config/initializers/simple_form.rb file, find the label class line and set it to:
config.label_class = 'control-label'
Also, if you are using bootstrap, you can do a few other things in this file. This might also help you:
SimpleForm.setup do |config|
config.wrappers :my_wrapper, :class => 'control-group',
:hint_class => :field_with_hint, :error_class => :field_with_errors do |b|
b.use :html5
b.use :placeholder
b.optional :maxlength
b.optional :pattern
b.optional :min_max
b.optional :readonly
## Inputs
b.use :label
b.wrapper :my_wrapper, :tag => 'div', :class => 'controls' do |ba|
ba.use :input
ba.use :error, :wrap_with => { :tag => 'span', :class => 'label label-important' }
ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' }
end
end
config.default_wrapper = :my_wrapper
config.boolean_style = :nested
config.button_class = 'btn'
config.error_notification_tag = :div
config.error_notification_class = 'alert alert-error'
config.label_class = 'control-label'
config.form_class = 'form-horizontal'
config.generate_additional_classes_for = [:wrapper, :label, :input]
config.browser_validations = true
end
According to this you have to do something along the lines of this:
f.label :first, label: 'Full and last name'

Pass Contest Id into URL for search in Index

I have two models, contest and submission. submission belongs_to contest and contest has_many submissions.
In the index action for submissions I have a search:
def index
contest_id = params[:contest_id]
#contest = Contest.find(contest_id)
if params[:search].blank?
#submissions = Submission.paginate(:per_page => 10, :page => params[:page])
else
#submissions = Submission.search(params[:search]).paginate(:per_page => 10, :page => params[:page])
end
#search = params[:search]
end
I think the right way to pass it in is through the search form in the submissions>index view:
<div class ="span12 row">
<%= form_tag submissions_path, :method => 'get', :class => "form-search pull-right" do %>
<%= text_field_tag :search, params[:search], :class => 'input-xlarge', :placeholder => 'Search by member, title or description' %>
<%= submit_tag "Search", :title => nil, :class => 'btn btn-primary' %>
<% end %>
</div>
And I have been able to come close using this:
<%= hidden_field :contest_id, #contest.id %>
In the form, but it's returning this in the url:
http://localhost:3000/submissions?utf8=%E2%9C%93&search=test&contest_id%5B%5D=&commit=Search
And an error:
Couldn't find Contest with id=
I've also tried this:
<%= hidden_field(:contest_id, :value => #contest.id ) %>
But it's returning similar url and error.
Right now, I'm stuck. If you have any idea, please let me know.
[edit - added html]
Before search:
<div class ="span12 row">
<form accept-charset="UTF-8" action="/submissions" class="form-search pull-right" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
<input class="input-xlarge" id="search" name="search" placeholder="Search by member, title or description" type="text" />
<input id="contest_id_5" name="contest_id[5]" type="hidden" />
<input class="btn btn-primary" name="commit" type="submit" value="Search" />
</form>
</div>
Here's what works from other links going to submissions:
From the submission show page:
<%= link_to 'Browse All Submissions', submissions_path(:contest_id => #contest.id), :class => 'btn btn-mini pull-right' %>`
and from the contest show page:
<%= link_to 'Browse All Submissions', submissions_path(:contest_id => #contest.id), :class => 'btn btn-mini pull-right' %>
Both of these pass the url "contest_id=5" which is what the controller needs to find a contest. The issue I'm having with search is finding the right syntax to get contest_id=5 to appear without the mumbo jumbo mucking it up.
This turned out to be an easy solution. Insert a hidden_field_tag in the search form:
<%= hidden_field_tag 'contest_id', #contest.id %>
This will pass the correct value into params:
http://localhost:3000/submissions?utf8=%E2%9C%93&search=new&contest_id=5&commit=Search

capybara Rails3 'cannot fill in'

This is so frustrating that after examining all stackoverflow queries on a related subject, having the tests seemingly pass before, I cannot get this simple thing to line up and pass. It cannot find a label "quality" in a form_for (#price).
And I fill in "good" in Quality
cannot fill in, no text field, text area or password field with id, name, or label 'price[quality]' found (Capybara::ElementNotFound)
My feature (abridged)
Scenario: Adding corn price
And I fill in "good" in Quality
My step (abridged)
When /^I fill in "([^"]*)" in Quality$/ do |text|
fill_in('price[quality]', :with => text)
end
My form:
<%= form_for (#price), :url => prices_path do |f| %>
<div class="field">
<%= f.label :quality %><br />
<%= f.text_field :quality %>
</div>
My source:
<div class="field">
<label for="price_quality">Quality</label><br />
<input id="price_quality" name="price[quality]" size="30" type="text" />
</div>
I've tried so many combinations to get it to pass, and I've run out of combinations to try, sam
What about use next:
When /^I fill in "([^"]*)" in Quality$/ do |text|
fill_in('price_quality', :with => text)
end