Capybara click on link which executes js doesn't working - ruby-on-rails

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

Related

How to run all Capybara tests as if all scenarios were tagged with "#javascript"

I can add the #javascript tag on individual scenarios, as well on entire features (by adding the tag to the top of each feature file). This works well, but instead of repeating the tag in every file, I'd like Capybara to treat all feature files as if the tag existed. The suite uses Poltergeist:
Capybara.javascript_driver = :poltergeist
I'd like to stick with this driver (to minimize changes), but don't see a way to configure it to always execute javascript. Is there a way to globally set javascript "on"?
Non-tagged tests run with Capybara.default_driver so
Capybara.default_driver = :poltergeist
would make all tests use poltergeist by default. If there were any specific scenarios you wanted to use the original default rack_test driver you could then tag them with #rack_test (assuming you're using require 'capybara/cucumber')
Just do
describe "Some test", :js => true do
it "bla bla" do
#your test
end
end
This way, JS will be enabled in every test.

Rails Capybara following render after form submit

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

How to test if a partial is rendering an image in erb, rspec, and capybara?

I'm getting started with rspec, capybara, etc, and I want to do some test driven development in Rails.
The specification I'm working with has very precise definitions for the appearance of the headers and the footers, and I figure that these are a good place to start learning.
For the footer, I want to have the following rule:
If the user is logged in, then the header contains just a logo image. The logo image should be a link to the user's landing page, which is determined by the rights the user has. If the user is not logged in, then the image is not a link, and four other links should appear in the footer as well, in a table.
Coding this is actually fairly straightfoward in erb, but I'm trying to Do The Right Thing, and make a series of tests here. My problems is that I can't seem to be able to test whether or not an image is shown on the screen. I've read the rspec book, but I don't see where it says something like 'shows this image found in the assets directory.'
So my setup is, in the views/layouts directory,
_header.html.erb
_footer.html.erb
_shim.html.erb
application.html.erb
I would think that I could test the footer partial directly, using something like:
require "spec_helper"
describe "rendering views/layouts/_footer.html.erb" do
#from https://www.relishapp.com/rspec/rspec-rails/v/2-8/docs/view-specs/view-spec
it "shows the logo" do
render :template => "layouts/_footer.html.erb"
rendered.should =~ "/images/mainlogo.png"
end
describe "rendering views/layouts/_footer.html.erb as admin" do
before do
FactoryGirl.create(:admin_user)
end
it "links to landing from the logo"
render :template => "layouts/_footer.html.erb"
rendered.should contain("link/to/admin/landing")
end
end
#repeat landing tests for various user types
And then, in other pages, I can simply test for the presence of the footer itself using something like
it should contain("footer")
My problem is, I can't even get off the ground to check to see if the image has been shown, much less if the image matches the right one in the assets directory. What should I be doing here?
The above code for testing the presence of the image (just the first describe/it block, not the stuff with the 'as admin' or the 'should contain') gives me the following warning and error:
DEPRECATION WARNING: Passing a template handler in the template name is deprecated.
TypeError:
type mismatch: String given
The first is probably due to me using syntax I don't understand, but the second seems to suggest that the comparison is with strings rather than assets. What's the syntax to compare images? Is there one?
Your type mismatch error is because you're passing a string to =~ which is a regular expression matcher. You can either change the string to a regular expression, or use the include instead. I'd go with include just because it's more readable:
rendered.should include("/images/mainlogo.png")
To get rid of the deprecation warning, just remove the .erb from the template name:
render :template => "layouts/_footer.html"

after_request in capybara (in rspec)?

We want to validate after every request that there is no escaped HTML or XSS on the page. In Cucumber, we have an AfterStep that does this (as long as the current page is not the same as the previous page).
Is there any way to do this?
EDIT: See https://gist.github.com/603295 for an example of an old (no longer working) version of what I'm hoping to find.
Rspec gives you these after hooks:
https://www.relishapp.com/rspec/rspec-core/v/2-0/docs/hooks/before-and-after-hooks
In short:
after(:each)
after(:all)
after(:suite)
This is the best I could come up with, which was pretty close (however, it's still only after every example, not after every request):
In my spec helper, I added something like this:
RSpec.configure do |config|
config.after(:each, type: :feature) do
# this is run after each example in Capybara, and I did stuff like
page.body.should_not match(UNESCAPED_REGEX)
end
end

How do you use the rspec have_selector method to verify XML?

I want to do some basic checking to ensure that an XML sitemap is being produced correctly but have_selector doesn't seem to be able to detect tags:
require 'spec_helper'
describe SitemapController do
render_views
before(:all) do
# code to generate factory data
# ...
end
# illustrating the problem
it "should be able detect nodes that are definitely present" do
get :index
response.should have_selector('url')
end
end
Every time I run the test I get the following error:
RSpec::Expectations::ExpectationNotMetError: expected css "url" to return something
The sitemap is being produced and when I debug the RSpec test and look at the response object I can see xml content:
ruby-1.9.2-p180 :001 > response.body
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n <url>\n <loc>http://test.host/panel ...
My sitemap is produced by the SitemapController and the view is located in views/sitemap/index.builder.xml.
Why isn't have_selector kicking in?
Capybara doesn't support XML responses. It always uses Nokogiri::HTML to parse the content, which produces unexpected results when given XML.
Adding XML support has been requested but was rejected by Capybara's maintainer.
Use should have_xpath('//url') instead. have_selector is for CSS.
See the Capybara README for more info.
As far as I can tell the have_selector (or have_xpath) can only come from Webrat or Capybara. You're right in your comment to John that you don't need a browser simulator to test the API.
You may be invoking Webrat or Capybara by mistake as they use visit instead of get AFAIK. So the variables they match against may never have been populated by the page and so will always return false.
Rails should handle the XML document natively if the response content-type is correctly set to XML. Try using the assert_tag or assert_content test helper as a basic check.
I would just use Nokogiri to parse the XHTML and run normal RSpec tests against that:
xml = Nokogiri::XML(response.body)
xml.css("expression").size.should == 1

Resources