Rails Functional test assert_select javascript respond_to - javascript

I am currently trying to write functional tests for a charging form which gets loaded on to the page via AJAX(jQuery). It loads the form from the charge_form action which returns the consult_form.js.erb view.
This all works, but I am having trouble with my testing.
In the functional I can go to the action but I cannot use assert_select to find a an element and verify that the form is in fact there.
Error:
1) Failure:
test_should_create_new_consult(ConsultsControllerTest) [/test/functional/consults_controller_test.rb:8]:
Expected at least 1 element matching "h4", found 0.
<false> is not true.
This is the view.
consult_form.js.erb:
<div id="charging_form">
<h4>Charging form</h4>
<div class="left" id="charge_selection">
<%= select_tag("select_category", options_from_collection_for_select(#categories, :id, :name)) %><br/>
...
consults_controller_test.rb:
require 'test_helper'
class ConsultsControllerTest < ActionController::TestCase
def test_should_create_new_consult
get_with_user :charge_form, :animal_id => animals(:one), :id => consults(:one), :format => 'js'
assert_response :success
assert_select 'h4', "Charging form" #can't find h4
end
end
Is there a problem with using assert_select with types other than html?
Thank you for any help!

So, the problem was that I should put javascript in .js and HTML in .html :P Kinda obvious.
I was putting html into a javascript file. I fixed it by simply renaming charge_form.js.erb to charge_form.html.erb.

Related

document.ready not firing?

This is NOT a case of not having jQuery loaded, but I do feel like I'm missing something else that's simple... On this staging site: https://hidden-tundra-8656.herokuapp.com/orders, once the page finishes loading, the "Camping & backpacking" should be auto-selected.
This is the code:
$(document).ready( function() {
console.log("about to trigger initial click")
$(".category-selector[data-id='"+gon.category_to_start+"']").click()
})
It's definitely not happening. Any thoughts? The only thing that I can think of is that the category-selectors are interpolated from Ruby, see view code below, so maybe that's causing it?
<div class="row">
<% #item_categories.each do |ic| %>
<div class="col-xs-6 category-box">
<div class="row category-row">
<div class="col-xs-12 table-display category-selector text-center" data-id="<%=ic.id%>">
<span class="labeler-response table-cell-display">
<%= ic.name %>
</span>
</div>
</div>
</div>
<% end %>
</div>
A little bit more info.
The console.log in the code is not triggered, and gon.category_to_start is defined. ALL of the other jquery on the page is working perfectly.
On this page, it is loading the application.js and a separate orders/new.js that contains the code in question. It loads jquery first, then application.js then new.js. For argument's sake, I just tried to load the code snippet into application.js and it didn't work there either. This works fine in local server.
If you're using Turbolinks (default if you setup a rails project), you should use page:load as an event.
$(document).on("page:load", function() {
console.log("about to trigger initial click");
$(".category-selector[data-id='"+gon.category_to_start+"']").click();
});
NOTE:
If you're in production mode, please make sure that you run bin/rake assets:precompile to keep your assets up-to-date.
The issue seems to be with this line
$(".category-selector[data-id='"+gon.category_to_start+"']").click()
There is no reference to gon.category_to_start so probably data-id is getting some undefined value.
Also you can check if the console.log is logging any value
"Camping & backpacking" should be auto-selected.
But I am seeing category-selector is on a div element. Do you mena to select the div, since auto-selection works on checkbox or radio button
Why include the data-id in the selector?
You can $('.classname').trigger.('click') on document ready
facepalm answer: precompile assets

Rails: How to show dynamic html content in the browser without escaping it and without causing XSS attack

I want to diplay html content in the browser without escaping it.my code is as below.
<% #mydata = "<p>paragraph</p><h1>Test</h1><script>alert('got your cookie')</script><h1>another test</h1>" %>
<%= sanitize #mydata %>
here i can't use raw method because raw method will execute malicious javascript code and hence i am using rails sanitize method. but the problem is that rails sanitize method deleting <script>alert('got your cookie')</scipt> line and not showing it in the browser.
I am getting output as below
paragraphTestanother test
My expected output is as below
paragraphTestalert('got your cookie')another test
is there any way to unescape html content and escape only javascript content from the user input?
Thanks,
in rails you can whitelist tags:
<%= sanitize #comment.body, tags: %w(strong em a), attributes: %w(href) %>
http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html
other ways how to do it:
option 1
require 'cgi'
CGI.escapeHTML('<h1>hi</h1><script>aeuoau</script>')
# => "<h1>hi</h1><script>aeuoau</script>"
http://ruby-doc.org/stdlib-2.2.0/libdoc/cgi/rdoc/CGI.html
option 2
if you are building something like blog website where you would display html code:
http://coderay.rubychan.de/
https://github.com/rubychan/codera
option 3
if you just want to remove malicious HTML and keep common text tags like p, b, ul, ....
raw(simple_format('<h1>hi</h1><script>aeuoau</script>'))
# => "<p><h1>hi</h1>aeuoau</p>"
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-simple_format
note: simple_format will "format" your code => would wrap \n in <p></p>, etc.
other gems
https://github.com/rgrove/sanitize
https://github.com/flavorjones/loofah

Use foundation abide to validate length of a text field?

I'm using foundation in a rails app and I'm looking for a way to validate the length of text fields in a form: I'd like to display an error when the text field contains too many characters (but not when it's empty).
I tried to use Foundation's abide and create custom named patterns as explained in the docs.
Here are the contents of my application.js file including the custom patterns upon Foundation initialization:
$(function(){
$(document)
.foundation()
.foundation('abide', {
patterns: {
short_field: /^.{,40}$/,
long_field: /^.{,72}$/
}
});
});
And here is my form code in the view:
<form data-abide>
<div class="long-name-field">
<input type="text" pattern="long_field" placeholder="Long Field">
<small class="error">Too long.</small>
</div>
<div class="short-name-field">
<input type="text" pattern="short_field" placeholder="Short Field">
<small class="error">Too long.</small>
</div>
</form>
The problem is that when I load my form page all the fields always display the error message, whether they're empty, filled under their character limit or exceeding their character limit.
Anyone successfully used abide to do something similar (or knows a better way that is not using custom named patterns)?
Cheers.
I finally managed to make it work!
The problem was that /^.{,40}$/ is not a valid regexp syntax, you have to use /^.{0,40}$/ explicitly.
I mistake it with the /.{5,}/ syntax that you can use to impose a only a lower limit.
I could not make the javascript abide work in my Rails 4 app, so I just added the regex directly as an attribute like so:
<%= text_area_tag 'answer', #current_answer,
:placeholder => 'required', :required => '', :pattern => '^(.){0,1000}$' %>
For validating minimum length only I use:
<%= text_area_tag 'answer', #current_answer,
:placeholder => 'required', :required => '', :pattern => '^(.){100,}$' %>

Different view-options in Rails

What is the best practise for creating a view page in Rails with different view-options, such as a basic view with mostly text and an advanced view with graphical features? More specifically, I would like to have a view page where the the user can toggle between a basic/advanced show view. Clicking the toggle button renders one set of divs corresponding to selected view. Should this be done though a form_for/if-else statement in html markup or is it better do to do it in javascript? I guess turning the <div id="id"> on/off could be done in javascript through:
$("#id").show()
$("#id").hide()
I have a problem understanding how a rails implementation is done, where do I put the if-else statement (i.e. if user basic view is toggled render <div id="basic">, else <div id="advanced">)?
<%= form_for ??? do |f| %>
...
<%= f.submit ??? %>
<% end %>
Edit 2:
<div class="row">
<div class="span6">
<div class="btn-group" id="basic-advanced" data-toggle="buttons-radio">
<a class="btn btn-small" href="#" id="basicbutton">Basic</a>
<a class="btn btn-small" href="#" id="advancedbutton">Advanced</a>
</div>
</div>
</div>
<div class="container" id="basic">
This is the basic view
</div>
<div class="container" id="advanced">
This is the advanced view
</div>
Now in javascript I have the following:
$("#basic").toggle();
$("#basic-advanced").click(function (){
$("#basic").toggle();
$("#advanced").toggle();
});
I have added the above code, but how do I keep track of which viewing mode that the page is in? From the answers it seems like one could set an instance variable, #viewing_mode, to a value corresponding to the mode, but how should this be done? Through a form?
Update: I managed to achieve a toggle using a session variable, and an if/else statement, the procedure is described here: Session variable not persisting after switch.
If you are using jQuery.show() and jQuery.hide() that means you need both the basic and advanced div tags rendered. Rails needs to render them both. You can just have toggle display:hidden css, here I did that with variable #use_advanced.
<div id="advanced" <%= (#use_advanced) ? '' : ' style="display:hidden"' %>>...
<div id="basic" <%= (#use_advanced) ? ' style="display:hidden"' : '' %>>...
To toggle between the two you could have a button: <button>toggle</button>
$('button').click(function () {
$('#advanced').toggle();
$('#basic').toggle();
});
There are some different cases:
1) if you are able to change your view using CSS only - then you should enclose all the page inside classified div:
<div class='my-style'>
...
</div>
2) if first solution is not applicable then you may use if-else statement:
<% if #my_style_selected %>
<div>My style</div>
<% else %>
<div>Default</div>
<% end %>
3) finally, if neither solution suits you. You may write some JS to dynamically replace your divs. The best solution is to replace some parts of the page using AJAX. If you will render both variants and hide one of them - that will almost double your page load time.
Given that yiou are using rails I would look into using layout for different views rather than having conditional logic.
For more info see rails 3, how add a view that does not use same layout as rest of app?
Here's a JavaScript object (written in CoffeScript) that will allow you to switch between as many modes as you like using a convention:
class ModeSwitcher
constructor: ($area, modes) ->
$area = $ $area
me = this
bindToggle = (mode) ->
$area.find('a.toggle.' + mode).click ->
me.toggle mode
$ ->
bindToggle(mode) for mode in modes
toggle: (mode) ->
$('.mode').hide()
$('.' + mode + '.mode').show()
Here's an example of how you could construct the object (JavaScript/jQuery):
var switcher = new ModeSwitcher('body', ['basic', 'advanced']);
$(function() {
switcher.switch("<%= #mode %>");
});
The #mode instance variable is set in the Rails controller and says which mode the view should start out in:
#mode = params[:mode] || 'basic'
As for how it works by convention, you would have sections like this:
<div class="basic mode">...</div>
<div class="advanced mode">...</div>
And you would have links like this:
<a class="toggle advanced">Switch to advanced mode</a>
<a class="toggle basic">Switch to basic mode</a>
When constructed, the object will iterate through all the declared modes and look for the toggle links. It will then bind the toggling function to those links.

Rails problem accepts_nested_attributes_for

I have this problem:
My web application has a form where the users can customize their profile.
In each profile can be specified many skills and I want to allow the users to press one button (add new skill) in order to specify as many skills as they want.
So this is the controller code:
accepts_nested_attributes_for :skills, :allow_destroy=>true, :reject_if => lambda {|a| a[:name].blank?}
This is the form (just the part with the nested attribute skill):
<%= f.fields_for :skills do |builder|%>
<div class="field">
<%= builder.label :skill %>
<%= builder.text_field :name%>
<%= builder.hidden_field :_destroy %>
<%= link_to 'remove', '#', :onclick=>'removeField()'%>
</div>
<%end%>
This form work perfectly and shows each skill of the user, it allows editing etc. The problem now, is that I want to add a link to "add new skill" so a javascript function that change the form and add new skill input field, I really have no idea to how to act, mainly because the nested attributes have specific id and name in the form that I don't understand:
<input id="profile_skills_attributes_0_name" name="profile[skills_attributes][0][name]" size="30" type="text" value="Mathematicansszz" />
It also add another hidden input field with the id of the skill (impossible to predict if the skill is not created), make impossible to create new skill from an HTML static pages?
<input id="profile_skills_attributes_0_id" name="profile[skills_attributes][0][id]" type="hidden" value="3" />
Any idea or workaround ? Thank you
I have written a gem that can handle that makes handling nested forms dynamically easier: cocoon.
The gem works with the standard rails formhelpers, but also with formtastic or simple_form.
I would also advise you to checkout formtastic or simple_form, as those are awesome gems to make form-handling easier. But as with HAML, that is a personal choice.
fields_for creates an array of fields. The "0" in the name represents the index in the array. Since you're creating new records you can simply ignore the hidden id field.
So via javascript you just need to do two things:
1. Count the number of existing inputs for the child collection in order to get a new index.
2. Add a new text field using the new index.
This is relatively easy to do with jQuery using a wildcard selector like $('input[name$="][name]"]').length; to retrieve a count (for the new index). If you have another field for array with name fields you may want to use a regex selector instead (via plugin). An easier way might be to just add a class to each of your skill name inputs and use that class as the selector when counting.
To append the new input see:
http://api.jquery.com/append/
If you're not using jquery, then it should be similar in other frameworks with a little googling.

Categories