Capybara doesn't render page in test - ruby-on-rails

I have a Rails project with Backbone and Capybara for integration tests.
In the test I'm running save_and_open_page and it successfully opens the page in browser with valid Javascript.
But when I'm running puts page.body (right after save_and_open_page) it gives me
//skipped
<div id="main">
Loading...
</div>
</body></html>
And then no have_content and other selectors work.
How is it possible that it saves and opens valid page but has wrong page body?
How to fix it?

The default driver for Capybara is Rack::Test. Your page probably requires javacript which means that Capybara's default driver is not rendering everything correctly. Just set Capybara.default_driver = :selenium. This way the javascript is run correctly.
See also link, which explains how to change the driver for only one testcase and not the whole test suite. Note that if you use selenium as the driver the method save_and_open_page probably won't work.

I needed to add to spec_helper.rb the line
require 'capybara/rspec'
and use default browser driver

Related

How to parse a Google search page to get result statistics and AdWords count using Nokogiri

I am trying to scrape a Google search page to learn scraping, using code like this:
doc = Nokogiri::HTML(open("https://www.google.com/search?q=cardiovascular+diesese"))
I want to get the result statistics text in every search page:
but I can't find the position of the content in the parsed HTML. I can inspect the page in the browser and see it's in a <div id="result-stats">. I tried this to find it:
doc.at_css('[id="result-stats"]').text
Your use of CSS is awkward. Consider this:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
<body>
<div id="result-stats">foo</div>
</body>
</html>
EOT
doc.at_css('[id="result-stats"]').text # => "foo"
doc.at('#result-stats').text # => "foo"
CSS uses # for id, so '[id="result-stats"]' is unnecessarily verbose.
Nokogiri is smart enough to know to use CSS when it looks at the selector; In many years of using it I've only fooled it once and was forced to use the CSS/XPath specific versions of the generic search or at methods. By using the generic methods you can change the selector between CSS and XPath without bothering with the method being called. "Using 'at', 'search' and their siblings" talks about this.
In addition, just for fun, Nokogiri should have all the jQuery extensions to CSS as those were on the v2.0 roadmap for Nokogiri.
You need to use Selenium WebDriver to get dynamic content. Nokogiri alone cannot parse it.
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.get "https://www.google.com/search?q=cardiovascular+diesese"
doc = Nokogiri::HTML driver.page_source
doc.at_css('[id="result-stats"]').text

Script tags with type 'text/x-handlebars' disappear from the page when tested by Capybara

Project setup:
Server: Rails & Haml
Testing: Capybara - Cucumber - Poltergeist - PhantomJS
Client side: Ember.js
There is a page that uses only one component of Ember (without loading full-stack of route-controller-model) and for some reason, script tag with the template for this component is not rendered on the page, in tests only.
Component works well on page if tested manually, no errors or warnings displayed. If type is differ from 'text/x-handlebars' it will be rendered. There is no such problem for other Ember pages.
Sample markup:
_form.html.haml
=render 'ember/templates/components/foo_bar'
.row
.span12
<form markup>
ember/templates/components/foo_bar.html.haml
%script{type: 'text/x-handlebars', data:{'template-name' => 'components/foo-bar'}}
.input-append
<template markup>
How can I render this template on page?
Just a workaround rather than a solution, but worked for me:
Haml replaced with handelbars (.hbs) template
Template moved to 'templates' folder
'templates' folder added to application.js manifest
Ember-rails do the rest - compile & include handlebars code into page
Just add 'js: true'
it 'tests the script on presence', js: true do
. . .
end

Using javascript global window variables and integration testing

There's this nifty stackoverflow post on passing variables to Javascript. It echos this railscast episode. The technique works like a charm for configuring a jquery datepicker, but cause all my javascript integration tests to fail.
Here is the code in application.html.erb
<script type="text/javascript">
<%-# commented line -%>
window.sDateFormatLocal = "<%= t 'date.formats.js_date' %>"
</script>
This is a datepicker initialization that uses it
$("input.datepicker").datepicker({
dateFormat: sDateFormatLocal,
onClose: function(value, ui) {
console.log("regular old datepicker");
}
}
It appears to work very well. The only problem, all my integration tests with 'js: true' now fail. Here are the errors I get.
Capybara::Poltergeist::JavascriptError:
One or more errors were raised in the Javascript code on the page:
ReferenceError: Can't find variable: sDateFormatLocal
When I run in browser (Chrome, Firefox) there are no errors or warnings in the console.
For completeness, a typical spec looks like this:
describe "The root" do
it "should load the page and have js working.", :js => true do
visit root_path
page.should have_content "Hello world"
end
end
Is there a setting I am missing to allow variables like this in poltergeist?
If your datepicker function is not in jQuery document ready function or similar methods such as window.onload you'll have trouble.
By default the application.js will be loaded in head, and the JS code in your html.erb later. The html and assets are loaded by browser in parallel, and very likely assets will finish loading at first. If you execute the function right away instead of waiting for document ready, the variable is undefined.
If you missed that, put such code in ready block.
A better practice for exporting server variable is, instead of put it in html body, put it on head before application.js so you won't have any problem on undefined variable.
Just to follow-up on this, in case someone in is debugging a similar problem. It turned out in this case, not every view was using the same template. For instance, the signin screen has a different head. That was causing this not to load in certain circumstances, yet not others, like the ones where my tests were failing. Bottom line, make sure when you replicate your tests, you are doing it exactly as the tests do, like in my case, passing through a signin screen.

Using Nokogiri to scrape data: "undefined method `text'"

I am using Nokogiri in my Rails application to scrape information from a website but am getting:
NoMethodError: "undefined method `text' for nil:NilClass".
This is sample code:
require 'nokogiri'
require 'open-uri'
url = "https://btc-e.com/exchange/btc_usd/"
doclink = Nokogiri::HTML(open(url))
doclink.at_css(".orderStats:nth-child(1) strong").text
I am trying to pull in the "Last Price" listed in the URL. I used the "SelectorGadget" Chrome Add-in to find the CSS description. I also tried using .orderStats strong but got the same no method error. How do I fix this?
The page you are referring to uses JavaScript to populate itself. Since Nokigiri doesn't execute JS, the page Nokigiri fetches is pretty useless:
<html>
<head><title>loading</title></head>
<body>
<p>Please wait...</p>
<script>/* POPULATES THE PAGE */</script>
</body>
</html>
One solution would be to use a scraper that executes JS, e.g. Capybara+PhantomJS. Here's an article that describes how: http://www.chrisle.me/2012/12/scraping-html5-sites-using-capybara-phantomjs/. Google for more info.

Capybara: How to test a stylesheet of a page?

I want to have the ability to test the correct swapping of a stylesheet in my test suite. With this post about testing the page title using Capybara, I thought I would be able to test any link tags in the head section of the page. But it seems I am mistaken.
With a step like this:
save_and_open_page
page.should have_xpath("//link") # just something as simple as this, first.
save_and_open_page generates a HTML like this (with some stuff removed for brevity):
<head>
...
<link href="/home/ramon/source/unstilted/public/system_test/stylesheets/fancake/css/2.css?1323572998" type="text/css" class="jquery-styler" rel="stylesheet">
...
</head>
But I get this failure:
expected xpath "//link" to return something (RSpec::Expectations::ExpectationNotMetError)
Given all that, how do I test a stylesheet?
Thanks!
If you want to check that a CSS file exists on a page, then you can do the following:
page.should have_xpath("//link[contains(#href, 'style.css')]")
That'll check whether there are any <link> elements where the href attribute contains style.css. The error about "expected xpath to return something" means that the XPath you provided didn't actually exist - why it thinks that, I'm not sure, as you have a perfectly valid <link> tag in the HTML you've provided.
When I am checking for a css what I do is something like
expect(page.body).to include('/home/ramon/source/unstilted/public/system_test/stylesheets/fancake/css/2.css')

Resources