How can I use VCR with Rails 5.1 system tests? - ruby-on-rails

Many things on the web seem to suggest that VCR can be used with Capybara.
I have three problems.
This doesn't make much sense to me, because the test driver and the application code don't share memory.
I'm not finding full recipes on how to set this up.
I'm finding bits and pieces of how people have set this up, but it's outside of the context of rails 5.1, which does the capybara setup behind the scenes.
How do I configure a Rails 5.1 app, Capybara, and VCR to work together for system tests?
(My headless browser is phantomjs, driven by poltergeist. But I don't need to intercept requests from the browser, only server-side requests. If I needed to intercept from the browser I would probably use a full http proxy server, like puffing-billy.)

I'm assuming you mean Rails 5.1 since Rails 5 doesn't have system tests.
The copy of the application Capybara runs for testing is run in a separate thread, not a separate process. This means they do have access to the same memory, and loaded classes
There is nothing special required for configuring WebMock or VCR beyond what their READMEs already provide
The setup of Capybara and how Rails handles it is irrelevant to the configuration of WebMock or VCR. Additionally, even when using Rails 5.1 system tests all of the normal Capybara configuration options are still usable.
That all being said, there are a couple of things to be aware of here. Firstly, WebMock/VCR can only deal with requests made by your app (not from the browser which you stated you don't need) and it's generally better to use faked services (if possible) rather than WebMock/VCR when doing end to end system tests since there is less interference with the code under test.
If this doesn't answer your issues, post a question with a specific issue you're having, the code that's causing your issue, and the error you're getting.

Related

Changing the value of a session variable in RSpec/Capybara/Selenium

I'm starting to write feature specs for a Rails application using Rspec with Capybara and Selenium to drive the browser.
While executing one of the specs I want to change the value of a session variable. Eg: I want to set session[:user_id]=123 so that I can test features in my application without having to go via the login screen every time.
When using Capybara with the default rack_test driver, the rack_session_access gem works for accessing the session. But it doesn't seem to work when using the Selenium driver.
And yes, this question has been asked before, but no satisfactory answer has been given.
Short answer, you don't. Longer answer, that's completely against the point of feature tests which are meant to be end to end.
That being said, if for performance reasons you want to short circuit the login, most authentication libraries provide a test mode that will allow you to do that - devise via the Warden TestHelpers for instance

Using PhantomJS in Ruby on Rails application

I would like to use PhantomJS as part of my main application lifecycle to take screenshots of a remote URL submitted by the user.
I'm familiar with using Poltergeist in conjunction with Capybara/Rspec. But how would I go about initializing the page object manually?
To initialize a capybara session in your app you can just do something like
session = Capybara::Session.new(:poltergeist)
( as documented here) and then rather than using page just call Capybara methods on session. One thing to note is that if you're going to test the app with Capybara too you will probably want to register a separate driver for the app and testing - https://github.com/jnicklas/capybara#configuring-and-adding-drivers . Also since Capybaras config is not thread-safe changing any of Capybaras setting would potentially affect both the test session and the in app session.
A far better solution may be to setup a separate Node.js service which runs phantom.js - in fact there are quite a few projects that provide a ready made screen capture webserver / console command.
Capybara is a testing tool and invoking a javascript runtime via ruby adds tons of overhead as well as not being thread-safe. The fact that it is not designed to be run in production is also a pretty big concern.
Instead you would simply call your screenshot service via HTTP or by running a shell command from Ruby.
I really like phantomjs in Rails app.
My suggest are using:
watir (https://github.com/watir/watir)
phantomjs (http://phantomjs.org/download.html)
You can take a screen shot very easy by using follow this: http://watir.github.io/docs/screenshots/
And if you want to use Page, i thinks you should see PageObject in here: https://github.com/watir/watir/wiki/Page-Objects

Making remote web requests in rspec

I have a php app that is going through a migration to rails. We are currently sharing the session from php to rails using memcached. The problem that has arisen is now testing has become difficult. I can't make remote requests using capybara to write functional that really test the full application.
The only solution I have come up with is mocking out the memcached communication, which isn't what I really want in integration testing.
Does anyone have any better options for this? I've tried other capybara drivers, such as mechanize, but I can't get external pages to load.
Have you tired Culerity driver?: Capybara::Session documentation
# NB! untested!
require 'capybara/session'
session = Capybara::Session.new(:culerity)
session.visit('http://www.google.com')
session.fill_in('q', :with => 'Capybara')
session.click_button('Search')
session.should have_content('Capybara')

Ruby on Rails: Best way to test a failed call to a third party API

I call a third party web service right now as part of my application. I am using the RestClient gem in order to do this. There are a ton of tools available to do the same thing, so that should not matter.
What I'm curious about is having good enough tests, nothing too fancy, where I can simulate how my application responds when the third party web service is unavailable for whatever reason. Be it that I exceeded a rate limit or a timeout due to network latency/complications, I just want to be able to take something like an HTTP status code and test what my application does in that event.
What's the best way to do this with Test::Unit? Right now the call to the third party service is encapsulated inside of one of my controllers. I have a simple module with some wrapper methods for the different end points of the remote service. I just want to make sure that my application does the right things when the service is or isn't available.
Is using an additional framework next to Test::Unit that can 'stub' the right way to go about doing this? Obviously I can't force a network timeout and starting to hack with things like IPtables just for tests is not worth the time. I'm sure this problem has been solved a million times as integrating things such as Facebook and Twitter into web applications is so popular these days. How do you test for failure when reaching those APIs in a robust/controlled format?
I would recommend using something like webmock to mock all of your http requests (not just to mock a failed request); it'll greatly speed up your test suite instead of having to actually hit the third party service every time you run the tests.
Webmock supports Rest Client and Test::Unit. Just put this code in your test/test_helper.rb file:
require 'webmock/test_unit'
As an example, to test a network timeout:
stub_request(:any, 'www.example.net').to_timeout
RestClient.post('www.example.net', 'abc') # ===> RestClient::RequestTimeout
railscast: 291 (subscriber only) talks about testing with VCR and rspec (i know, not it's not Test:Unit)
anyway you could look into using VCR for this sort of thing

Good practices for Integration Tests for my rails app external endpoints?

I'll keep it short, I've got a rails app which communicate with other apps, some using SOAP (non-rails apps of course...) and others with REST. I'm making integration tests to ensure that my endpoint wrapper classes have correct mappings and setup. However, they are executed by default by rake test which makes it slow and fragile. I wish to run unit tests frequently and integration tests "on-demand" only. How do you do that?
What're your preferences wrt such integration testing?
How deep do you unit test and/or mock?
Do you replicate whole SOAP or REST xml responses in stubs?
Do you create "external endpoint" integration tests at all?
Update Q: How to exclude a test-dir while running rake test ?
If you go by what the Rspec/Cucumber folks suggest, then the integration test level is an inappropriate place to mock your data, because in some respects, it defeats the purpose of the integration/acceptance test. However, you have to mock stuff like paypal transactions, right? In my current project, I am facing a lot of this, and here are some of the solutions I am implementing:
Tagging tests that wont work in certain contexts. In my example, lots of servers live behind firewalls and so my tests dont pass if I am at home and not using vpn. So, in cucumber I can tag these as #firewall and tell it to run tests that are not tagged firewall. I'm pretty sure Rspec 2.0 supports this feature as well.
Mocking service requests. Yah, its probably a bad idea, but I am at a loss on how to do it otherwise with any kind of predictability. I have a separate test suite to affirm that the services are running, and from my rails app, i am assuming they are working properly. An example of this would be LDAP. And yes, in these circumstances, I tend to use a real response and do something like. response = double('response') ; response.expects(:data).and_returns('my xml here')
I do think regardless of the complexity of the system that end point tests are really important. I am really enjoying cucumber, it provides me 95% of what I need to do in functional tests, and so I end up writing fewer of these tests and more of the entire workflow tests.
The solution is VCR.
Excluding endpoint integration tests from rake test and being able to isolate and run them with rake test:endpoints was solved with only a few lines of code. I have to admit though, I spent a whole lot of hours swearing and cursing. There should be more documentation and explanations in the railties source. Ruby code like that tend not to be very self-explanatory, IMO.
Well, here it goes:
create your task: lib/tasks/slow_tests.rake
require 'rails/test_unit/railtie'
desc "Runs all endpoint integration tests."
namespace :test do
#hooks on to the test task through the 'test:prepare'
#For details, check the railties gem (v3.0+) lib/rails/test_unit/testing.rake,
#look for "task :test" and "namespace :test"
TestTaskWithoutDescription.new(:endpoints => 'test:prepare') do |t|
t.libs << 'test'
t.pattern = 'test/endpoints/**/*_test.rb'
end
end
Now I may put my fragile endpoint integration tests in the test/enpoints directory, running them whenever I want (not often)
Note: this supposes test/unit or shoulda.
You should write a thin layer around external APIs (Facade/Wrapper) and use the vcr-gem to "stub" network calls.
You can get more information from my article on rails test architecture.

Resources