I have an integration test that fails for a page that depends heavily on javacript. The same page runs just fine from the browser.
Simplifying the test to a bare minimum I found out that just testing for the presence of a selector that is added by javascript after the page load, would fail.
After precompiling the test assets and using save_and_open_page I found that the handler for the jQuery ready event is not running during the integration test.
I didn't find any references to this problem, so I guess I'm doing something wrong.
Can anyone help me figuring this out?
I'm using using rails 3.2.11, RSpec 2.13.0, Capybara 2.0.3 and capybara-webkit 0.14.2
By default Rails uses webdriver which doesn't handle JS. If you want JS support you'd need to use one of the JS-aware drivers, like Selenium (which runs full featured browser), capybara-webkit or poltergeist (which are headless webkit browsers). There are many others but these three are most popular.
I solved this problem for me by examining my AJAX request. The problem was that I was requesting a 'http://..." instead of '/' of my page. This meant that it raised a CORS ('ajax request from outside the domain') even though the request looked like it was coming from inside the domain.
My original symptom was 'javascript-inserted HTML elements are not on the page when testing using Capybara with Poltergeist or Selenium (but are on the page when running the application).'
Related
I'm working on an advertising application, where there is some cross-domain JS. I'd like to write tests that verify that the cross-domain JS is working as intended.
My first thoughts are that I would need to be able to
visit some_url_thats_not_my_rails_app
However, Capybara throws a "No Route Matches", since it obviously goes to only relative paths, and is intended for testing your OWN website. But I really need to go on ANOTHER page, and verify that things like the serialized token are identical.
Is Capybara the right tool for this? If so, what do I need to do to force non-relative paths?
Yes, Capybara is right tool for it. You can also use Ruby with Selenium webdriver(Would be awesome with page object gem) or Ruby with Watir webdriver.
To visit and test any web application, you can use Ruby and Capybara. For this you need to set app_host. Add this one in support/env.rb:
Capybara.app_host = "http://flipkart.com"
And in hooks.rb
Before do
visit('/')
end
You can use Capybara with Selenium webdriver and you will be good to test any deployed application in production, staging or prep env.
What are the differences between PhantomJS and capybara-webkit?
What are the advantages of capybara-webkit over PhantomJS?
Which of the two is the most efficient tool?
Others ...
poltergeist is the capybara driver for PhantomJS, a headless browser which is built on WebKit. capybara-webkit is a capybara driver which uses WebKit directly.
poltergeist/PhantomJS has some big advantages over capybara-webkit:
In my experience poltergeist/PhantomJS always times out when it should, whereas capybara-webkit sometimes hangs.
Its error messages are much clearer. For example, it will actually tell you if it can't click an element that is on the page because there's another element in front of it.
It can be told to re-raise Javascript errors as test errors (by instantiating the driver with js_errors: true).
PhantomJS is much easier to install than standalone WebKit. PhantomJS provides a nearly dependency-free executable that you can download, while standalone WebKit has many OS library dependencies which you may have to upgrade or otherwise fiddle with.
TL;DR
Poltergeist/PhantomJS is easier to set up
Poltergeist/PhantomJS has less dependencies
Capybara-webkit is more stable and reliable and it’s better for CI
Long:
I have been using Poltergeist + PhantomJS for more than one year. My largest project has a lot of Ajax calls, file uploads, image manipulations, JS templates and pure CSS3 animations.
From time to time, Poltergeist and PhantomJS generated random errors.
Some of them were my mistakes. Testing Ajax is tricky. A common error was that at the end of the successful test the database_cleaner gem truncated the database, however, one Ajax call was still running and generated exception in the controller due the empty database. This isn’t always easy to fix unless you want to use sleep(). (I do not).
However, many errors with Poltergeist were not my mistakes. I have a test which does the same thing 30 times (for a good reason) and once in a while 1 of the 30 times it didn’t work. Poltergeist did not click on the button at all. It was a visible, not animated, normal button. I could fix it (by clicking on it again), however, that’s an ugly hack and feels wrong.
Sometimes the script that worked in all browsers generated random javascript errors with Poltergeist/PhantomJS. About 1 or 2 of 100 times.
With two different Ajax uploader plugin I have experienced that PhantomJS 1.9 and 2.0 behaves differently. 2.0 is more stable and consistent but it’s far from being perfect.
This was a huge pain with Jenkins. About every third run was a failure because 1 or 2 of the 400 features (js browser tests) generated random errors.
Two weeks ago I tried Capybara-webkit. It took me a couple of hours to migrate since they treat invisible elements differently. Capybara-webkit is more correct or strict in this. I noticed the same about overlapping elements.
Testing Ajax uploading and image manipulation requires custom scripts that I had to modify for Capybara-webkit.
I’m using Mac OS X for development, FreeBSD for production and Linux for Jenkins. Capybara-webkit was more complicated to set up than Poltergeist because it requires a screen and it has many dependencies. Only PhantomJS is truly headless and standalone. I could run PhantomJS on production servers if I wanted. I would not do that with capybara-webkit because of the dependencies.
Now I have 100% stable Jenkins CI. All the random javascript errors are the memories of the past. Capybara-webkit always clicks on the button I want it to click on. Javascript always works fine. Currently I have about 20-25 stable builds in a straight line.
For projects with a lot of Ajax, I recommend capybara-webkit.
My advice is based on the current, up to date versions in Aug, 2015.
capybara-webkit and PhantomJS both use Webkit under the hood to render web pages headlessly, i.e., without the need for a browser. They're different tools, however:
capybara-webkit serves as an adapter for Capybara, a Ruby gem that lets you write and perform high-level UI testing for a Rails or Rack app.
PhantomJS is a lower level tool that simply lets you run scripts against a web page. It can also be used to write UI tests as well (see Casper, for instance, or any of the other testing tools that build upon PhantomJS).
PhantomJS does not support HTML5 features like Audio/Video which really sucks.
I have non-Javascript specs and Javascript feature specs that use capybara/capybara-webkit.
I have some tests that I expected to fail when in non-Javascript mode, but they are passing. I've tried the functionality in my browser with Javascript turned off, and the functionality does indeed not work as expected. But in Capybara, it works.
I've also tried adding js: false to the individual test, to make sure there wasn't something hidden in my config turning it on. The spec still passes.
The selenium gem is not included in my Gemfile.
I see two possibilities: your tests are correct but there might be some reason why they pass unexpectedly, or your tests are incorrect and are passing for the wrong reason when you run them in Javascript.
A few suggestions for how to debug that apply to both possibilities:
Use a debugger. (If you have, let us know what you learned.)
Look at the Rails log from a single run of a spec to see what controller actions are called and in what order.
Use save_and_open_page to snapshot your page and see whether your spec should pass on what you're looking at.
Double-check your tests when run with Javascript:
Run them with the poltergeist driver instead of the capybara-webkit driver. It gives better error messages than capybara-webkit and can be configured to report Javascript error messages.
Use save_screenshot to take an actual screenshot of the page and verify that the spec is not passing for a spurious reason, perhaps because some content is off the screen.
If you want to be sure whether rspec is running Javascript, use ps to see whether there is a capybara-webkit or phantomjs process running.
Is it possible to use the page-object gem and capybara to automate Ruby on Rails testing? When I attempt to access a page object after starting up my test I receive the following error:
Unable to pick a platform for the provided browser (RuntimeError)
This makes sense as I think I'd have to pass the browser instance of capybara to the page-object, not sure if anyone else has tried this before.
There is a gem that lets you use the Page Object pattern with capybara: SitePrism. Find it here: https://github.com/natritmeyer/site_prism
Currently there is no support for capybara but it has been requested a few times. Part of the challenge is that the API was built upon selenium and watir which are much richer than capy and in it would be a very large undertaking to build add that functionality to the page-object gem to make capy behave the same way.
I've thought several times about splitting the page-object gem into a "basic" form that will allow capybara to utilize and an "advanced" form that will add the additional capabilities found in selenium and watir but haven't seen enough demand.
https://github.com/andyw8/capybara-page-object looks like it started existing in the last 8 months or so.
I want both, testing Ajax Content and normal toggled content through Javascript.
My Setup is:
- Rails 3.1
- Rspec (Edge)
- Cucumber (Edge)
- Capybara (Edge)
For expample, I want to have a Form, which shows particular fields only, if a certain type of this model is selected:
Article can be an external article (url)
or an internal.
Type "externa_url" should show 2 input fields and 2 checkboxes more then Type "article",
which has a body textarea instead.
Whats the best way to implement this, also with testing?
Should it be Server sided, so that partials are loaded, if a certain article type is selected,
or with javascript, toggle the needed html?
Actually inspired by Fransico (in the comments), I write down my knowledge.
I write my own answer, it may helps others too....
First I want to mention, I answer my question with – do integration testing only.
With cucumber and selenium.
And specific javascript testing with jasmine.
But, when integration testing with cucumber (edge) rails (3.1), capybara and selenium you have to be aware of some things:
Look, that you have all your gems updated!
1) Activate your driver, if you haven't already
features/support/capybara.rb
Capybara.javascript_driver = :selenium
2) At the moment only Firefox <=4 works with webdriver selenium for rails, as I found out hardly after hours of configuring and installing each component from scratch, like rack etc.
3) Capybara itself not handles much, which serves you for klicking e.g. on lists, jquery-tokeninput especially.
3.1) I use this for selecting an Item from the tokens in the list:
When(/^I select the option containing "([^\"]*)" in the Tag List/) do |text|
find("li:contains('#{text}')").click
end
You may find this method with "locate" instead of find, don't try this, api / driver has changed to find.
Find waits automatically and check for a Ajax respond in addition of dom finding elements.
4) Add your own helper / finder / click routines for your JS / Ajax responded code,
keep in mind, it is "only" an integration test, you may want to test your JS code with yasmine or another js test framework.
For furthter information also check Screencasts from Ryan Bates (http://railscasts.com), he covers several Topics on Testing Rails; check the latest one for Javascript e.g.
Or this blog: http://openmonkey.com/2010/04/09/javascript-testing-with-cucumber-capybara/
(thnx francisco)
hope this helps someone else as well.