In my rails controller i have:
def update
render #bill if #bill.update(bill_params)
end
On the form i have a remote true, so the render gets loaded on the page using ajax.
But in my capybara tests i have:
fill_in('bill_period', with: #bill.period)
fill_in('bill_groupname', with: #bill.groupname)
click_button 'update bill'
save_and_open_page
The page now opens in the render instead of the page it should be rendering on. It doesnt do this in the application itself only via capybara.
How to i prevent capybara from following the render?
It sounds like you're using the default capybara driver (rack_test) which doesn't support javascript. You need to switch to the selenium driver or another third party driver in order to have javascript (and hence ajax) support - https://github.com/jnicklas/capybara#selecting-the-driver
Related
I have a situation in Rails 5.2 where a controller is rendering a .js.erb file to the view literally, i.e. showing the javascript code in the view itself.
How can I get Rails to run the js.erb file instead of showing it as if it were a DOM file? It is taking the user away from a page I want the user to stay on.
# controller
def submit_custom_data
...perform some functions...
respond_to do |format|
format.js
end
end
# submit_custom_data.js.erb
console.log('submit_custom_data...');
... Other javascript ...
Additional Info
By preserving the browser console logs on Chrome, I see this:
Resource interpreted as Document but transferred with MIME type text/javascript: "http://localhost:3000/submit_custom_data/1068.js?c=1&d=10&db=1&s=8&tm=&w=3".
Navigated to http://localhost:3000/submit_custom_data/1068.js?c=1&d=10&db=1&s=8&tm=&w=3
This issue did NOT occur on Rails 4.2.7. After updating to Rails 5.2.7 (and updating the bundle), I'm now seeing these issues.
I am working on a web crawler which accesses remote pages by submitting search queries via the remote site's search bar:
class Crawler < PoltergeistDriver
def fetch_listing_page(query)
...
visit 'whatever.com'
fill_in('#seachbar', with: query)
find('#searchbar').native.send_key(:return)
...
end
end
I then use the page object to search for specific text inside the body like so:
class Crawler < PoltergeistDriver
...
def fetch_listing_data
...
page.all('some element', ...)
...
end
...
end
My question is can I mock this page object in my tests? My guess is that VCR / Webmock would not work as the requests are made from the client side (poltergeist in my case).
EDIT:
AS Thomas suggested, I ended up injecting PoltergeistDriver instance as a dependency. This way I can simply create another driver (PuffingBilly) for tests and mock the return of page.body with static html.
You can't use WebMock/VCR for this, but you can use a programmable proxy. PuffingBilly - https://github.com/oesmith/puffing-billy - is one that integrates nicely with capybara and poltergeist.
I have this code while using Capybara:
a = page.find(".show-link")
a.click
expect(page).not_to have_css(".someClass.hidden")
And I have link
<a class="show-link" href="">Show me!</a>
I have also js function bind to click event which removes hidden class from element:
$("body").on("click", ".show-link",function(){$('.someClass').removeClass('hidden');return false;});
But instead of executing my js function on click I get redirected to another page.
I tried to set href = "#", I tried to change <a> to <span> but doesn't work
script is not executed.
In your test definition, add :js => true, so:
describe 'some stuff which requires js', :js => true do
it 'will test this or that' do
...
end
end
Capybara will then use Selenium (default driver) to test your javascript functionality. It's quite cool as it uses an actual browser window.
Christian-G is correct if you are using rspec. If in case you are using Minitest the same idea applies but it would be executed something like:
test "this is my test" do
Capybara.current_driver = Capybara.javascript_driver
#test logic goes here
Capybara.use_default_driver
end
Ideally you would not change the capybara driver inline like this, but put them in your setup and teardown calls for the test. like this:
setup do
Capybara.current_driver = Capybara.javascript_driver
end
teardown do
Capybara.use_default_driver
end
This is also outlined in the Capybara documentation.
As it was already mentioned, you need to use some driver that supports js execution (webkit, poltergeist, selenium).
Also there should be only one matching element, i.e. if there's one element ".someClass.hidden" and another one ".someClass.shown" test won't pass
An one more option is that you have wrong usage of Capybara matcher:
expect(page).not_to have_css(".someClass.hidden")
should be
expect(page).to have_no_css(".someClass.hidden")
Why?
Capybara has logic to wait for something to happen, so in this case it checks that page has .someClass.hidden and immediately finds such element. If it were have_no_css it will find element, but then retry several times waiting for it to disappear
After updating to Rails 4.1, I got an interesting problem with Cucumber and Capybara in a new project.
Inside a view I placed some thumbnail portraits. The user is supposed to click on a thumbnail image link to receive more information about the person he has chosen. Through the magic of AJAX the information then appears below the thumbnails. Here's how i did it in the view:
<%= link_to( image_tag( ... ), "/controller/action.js&person=#{#person.nickname}", id: #person.thumb_id , remote: true) %
The controller follows the usual proceeding for cases like this with
respond_to do format.js end
etc.
Works perfectly in the browser and I love it.
However, Cucumber and Capybara don't work so smoothly. Here's the Capybara line that's giving me a lot of headache:
When(/^I click on one of the portraits to display the person's stuff$/) do
click_link("jack_sparrow_THUMB") # #user.thumb_id
end
Running the scenario with Cucumber, I receive this error message for the statement above:
Security warning: an embedded <script> tag on another site requested protected
JavaScript. If you know what you're doing, go ahead and disable forgery protection
on this action to permit cross-origin JavaScript embedding.
(ActionController::InvalidCrossOriginRequest)
The problem must have to do with this
http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
Just have a look at the CROSS_ORIGIN_JAVASCRIPT_WARNING provided ... :(
Is there anything I can do to make my tests run again without downgrading to rails < 4.1 or even turning off Request Forgery Protection in general? Help would be very much appreciated.
As per "CSRF protection from remote tags " from the rails guide:
In the case of tests, where you also doing the client, change from:
get :index, format: :js
To:
xhr :get, :index, format: :js
http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#csrf-protection-from-remote-script-tags
How would this be updated for Rails 3.1?
http://railscasts.com/episodes/88-dynamic-select-menus
I just can't figure out how to call the js.erb file and have it run the code to generate the javascript dynamically.
Might be something: in Rails 3.1, you're most likely using jQuery instead of Prototype. The example code on the Railscasts site is using good old Prototype instead of the new hotness that is jQuery (default javascript library in Rails 3.1).
Once all your jquery pipes are connected, having rails respond to and render your js.erb is the same as always. In your controller:
def country_selected
// whatever you need to do
respond_to do |format|
format.js
end
end
Then in your view directory, you have a country_selected.js.erb that you can put in whatever javascript you want to update the second select menu. (Remember you have to escape your shiz for it to work correctly) e.g.
<%= escape_javascript(params[:country]) %>
By the way, I think .rjs was moved out of Rails proper and into it's own Gem. Something else to keep in mind regarding Rails 3.1 vs. javascript.