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.
Related
I have working integration/feature tests using Rails 4, rspec-rails 3.6, and capybara 2.18. I am trying to get these tests to pass on pages that are being rewritten in a javascript framework (React). To do so, I need to use a driver such as Poltergeist instead of the default headless browser so that javascript can run on the test pages.
I've installed poltergeist 1.18. I add Capybara.javascript_driver = :poltergeist, no problem. The tests pass with the old (html-only) pages.
However just adding js: true to an existing, working test (that is, before changing the rendered page to to the new version) and the test fails with
Request to 'http://account.example.com/user/sessions/new' failed to reach server, check DNS and/or server status
Note that this url is using the account subdomain in our application, and this may be related to the issue.
Here is one of the failing tests, isolated.
feature 'Vistor tries to login', js: true do
scenario 'with valid login', :with_project_access_user do
visit new_user_sessions_url
fill_in 'user_session[login]', with: 'test#gmail.com'
fill_in 'user_session[password]', with: 'mysweetpassword'
click_button 'Log In'
expect(current_url).to match('http://account\.')
end
end
It's failing on the first line: visit new_user_sessions_url. This test passes if I remove js" true. In both cases, new_user_sessions_url is "http://account.example.com/user/sessions/new"
Using new_user_sessions_path instead of new_user_sessions_url doesn't work here because the subdomain is a required part of the route. If there is a way around the subdomain matching (without removing the subdomains -- they are used in our production app) that's a totally acceptable solution.
Since the test works without js: true, I have to assume that Capybara is doing something behind the scenes to handle the example.com domain. But how does adding js: true break this? And how can I fix this to get my existing tests to pass?
When not using js: true Capybara is using the rack_test driver which completely ignores hostnames, so the only thing that matters is the path. When you use js: true real hostnames are being used because the "browser" is querying them to figure out where to make its requests. It is your responsibility to make sure whatever hostname your app is generating urls with resolves to an ip the app is listening on. Easiest solution for that is to add entries to /etc/hosts mapping the domain/subdomain names you're using for testing to 127.0.0.1.
Note: Poltergeist uses PhantomJS which is equivalent to an 8-9 year old browser at this point. This means you're most likely going to run into issues trying to run React apps on it, and you should really look into upgrading to a driver for modern browser - Selenium, Apparition, etc.
I'm testing a JSON API for a model with a Carrierwave Uploader, but I'm only allowing uploads via a remote_url, so I need some way to get an HTTP address for a file in my public assets, since I know those'll always be around.
To put it another way:
When the Rails server is running, I have a static asset at "http://localhost:3000/assets/logo.png". I need the address of that file while Cucumber is running - aka, I need to serve a static file while running Cucumber, so that a different part of the Rails app can "download" that file.
Edit: These test are not run with a browser, although (as of recently), they are run with a session. I may be using Cucumber, but I have written no code to use or start Capybara.
If I'm understanding your question correctly. You may want to look into something like Fakeweb or Webmock to serve back/mock external requests.
I think you can get the root uri for the test server that cucumber starts by using these:
For capybara < 2.0:
Capybara.current_session.driver.rack_server.host
Capybara.current_session.driver.rack_server.port
Capybara 2.0:
Capybara.current_session.server.host
Capybara.current_session.server.port
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).'
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.
How can I run a watir test in the context of the app that's being tested? I'd like my test to browse the app and then access ActionMailer::Base.deliveries for emails or check models directly. This is how I understand what's being described here.
UPDATE: They probably use Capybara to be able to acces the email array and be in the context of the "server" which is instantiated just for the test.
I suggest checking out the Rails unit testing docs, then writing a simple Rails test case that starts your app - then try adding a line or two of Watir code to access your app:
http://guides.rubyonrails.org/testing.html
As far as I know you should be able to write a Rails unit test, then put Watir code inside one of your test methods - and if all goes well you should be able to instantiate your web app, use Watir to launch a browser to test it, and in the same method(s) perform non-Watir low-level testing (e.g. checking models/data/etc.)
I've never used Watir inside a Rails test, but I don't see why it wouldn't work.
Watir is about driving browsers to automate functional testing. You could I suppose use it for unit testing of the top level UI stuff, but more often in a 'unit test' context that would be done using a headless browser emulation, Capybara, celerity, or watir-webdriver using the headless option, purely for speed of operation since driving an actual browser can be slow even with a fast browser like chrome.
Most of the times people use Watir it's for more functional tests, often from a test runner framework like Cucumber, sometimes Rspec depending on your needs. You might combine that with other ruby code to access or create test data, to validate something made it into the DB from the UI, but everything in the Watir gem is all about the browser and interacting with it much like a human would, and driving the browser is it's function within the set of tools you might use.
I had the same need and found the following solution: https://stackoverflow.com/a/9687562/90741. I reproduce it here, as the linked question seems to be dead, with its owner...
I had the same need (Watir+RSpec), but the problem is: there is no Rack stack running by default during tests...
I found this solution:
In spec_helper.rb:
HTTP_PORT = 4000
test_instance_pid = fork do
exec 'unicorn_rails -E test -p %d' % HTTP_PORT
end
at_exit do
Process.kill "INT", test_instance_pid
Process.wait
end
Which start the test stack once for all spec tests, and kill it at the end. (In this sample, I am using unicorn, but we can imagine using any other server)
In the spec, I reuse the HTTP_PORT constant to build URL:
browser.goto "http://localhost:#{HTTP_PORT}/"