vcr with capybara-webkit - ruby

I'm using capybara-webkit to test integration with a third party website (I need javascript).
I want to use vcr to record requests made during the integration test but capybara-webkit doesn't go over net http so vcr is unable to record them. How would I go about writing an adaptor for vcr that would allow me to record the reqeusts?

Unfortunately, VCR is very much incompatible with capybara-webkit. The fact is that capybara webkit is using webkit, which is in c. Webmock and Fakeweb, which are the basis for VCR, can only be used for Ruby web requests. Making the two work together would likely be a monumental task.
I've solved this problem two ways:
The first (hacky, but valid) is to add a new javascript file to the application that is only included in the test environment. This file stubs out the JS classes which make external web requests. Aside from the pure hackatude of this approach, it requires that every time a new request is added or changed you must change the stubs as well.
The second approach is to route all external requests through my own server, effectively proxying all external requests through my server. This has the huge disadvantage that you have to have an action for everything you want to consume (you could genericize it, with some work). It also suffers from the fact that it could as much as double the time for the request to complete. However, since the requests are now being made by Ruby you can use VCR in all it's glory.
In my situations, approach #2 has been much more to my advantage thanks to the fact that I need ruby to manipulate the data so that I can keep my javascript source-agnostic. I was, however, using approach #1 for quite a while successfully.

I've written a small ruby library (puffing-billy) for rspec+capybara that does exactly this -- it injects a proxy in between your browser and the outside world and allows you to fake responses to specific requests.
Example:
describe 'fetching badges from stackoverflow API' do
it 'should show a nice message when you have no badges' do
# stub some JSONP
proxy.stub('http://api.stackoverflow.com/1.1/users/1/badges',
:jsonp => { :badges => [] })
visit '/my_badges'
page.should have_content("You don't have any badges :(")
end
end

Related

Is there a way to allow-list rspec tests that reach out to external domains?

We have several React apps that are embedded in our platform's controllers, served from S3 AWS domains. By default, rspec seems to disallow having <script src="https://some-external-dns.com/scripts.js"></script> in your code being tested, and instead asks that you "stub" your script request and response using something like this:
stub_request(:get, "https://foo-box.s3.amazonaws.com/assets/login-hero-manifest.json").with(
headers: {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
'Host' => 'foo-box.s3.amazonaws.com',
'User-Agent' => 'Ruby'
}
).to_return(
status: 200,
body: {
environment: "prod",
name: "feature-administration",
url: "https://foo-box.s3.amazonaws.com/assets/login-hero.js"
}.to_json
)
I get this in theory, but if we know this is a trusted domain, I would prefer us just resolve the response so we can test against it (also stubbing out hundreds of requests/responses across hundreds of tests feels completely unintuitive and unsustainable.
I am not super well-versed in Ruby/rspec, but I was hoping there was some way to allow-list code that comes back from foo-box.s3.amazonaws.com.
stub_request is actually a feature of a tool called WebMock, not RSpec.
WebMock is used to prevent your test suite from making slow, flaky external web requests while the test suite is running. If you were to actually make these requests to S3, your tests would fail any time S3 is down, or any network link between you and S3 goes down or slows down. (Unusual, for sure. But, it has happened.)
So, the code in your question is actually preventing you from making the HTTPS call to foo-box.s3.amazonaws.com and instead responding with the status code and body that you specify. This is a good thing. It will make your tests more reliable and performant.
As for whether or not this is sustainable, it depends on what you're testing. In the example above, the test seems to be validating the contents of a JSON file on S3. Which part of that test is important to you? Ensuring that the JSON in the file is correct? Or, ensuring that S3 returns the file you expect when you request it.
Since there's really no point testing that S3 returns the correct file when you request it -- Amazon's engineers have presumably done this for you -- you can safely ignore S3 here and focus on the content of the file. That means you can remove WebMock from the test and stick with plain old RSpec.
Assuming the file was generated dynamically and placed on S3 by your code (or maybe your build/deploy process), you should be able to test the portion of the code that generated the contents without testing the portion of the code that uploaded it to / downloaded it from S3.

Is there any way to start with a POST request using Selenide

I'm trying to start a Selenide test with a POST request to my application.
Instead of a simple open(/startpoint)
I would like to do something like open(/startpoint, stuff=foo,stuff2=bar)
Is there any way to do that?
I'm asking this because the original page which posts to this start point depends on external providers that are often offline (development environment) and so will often fail too early (and are not the subject of the test)
No, Selenium doesn't have the ability to do a POST request, unless you loaded a dummy HTML page with a <form> tag on it (as a unit test) and a submit button (such as src/test/resources/FormPage.html). So, the alternative is to build a HTTP post query from scratch using Apache HttpUtils library. I usually use the latter method (as an integration test), although the former would work I think.

Launch sinatra from a test/spec or another ruby script

I'm experimenting, and I'm trying to launch dummy Sinatra application from RSpec and kill it when the spec is finished. Something like:
# spec/some_spec.rb
before(:all)
# launch sinatra dummy app
end
after (:all)
# kill sinatra dummy app
end
it 'should return list of whatever' do
expect(JSON.parse(make_request('0.0.0.0:4567/test.json')))
.to include('whatever')
end
I could use system("ruby test/dummy/dummy_app.rb"), but how can I kill that process only? Does anyone know how I can launch the Sinatra inside a test (or from another ruby script)? I know about WebMocks, but I want to see if I can manage to make my test work this way.
Look under RSpec on "Testing Sinatra with Rack::Test". I'd suggest you use that code as boilerplate to get started.
Just add this to your describe block:
def app
Sinatra::Application
end
I would suggest you read up RSpec.
Since you want to test an external system, by the looks of your comment, instead of system "curl whatewer.com", you can use Net::HTTP to make requests and then test against the response.
Have a look at "Testing an external API using RSpec's request specs".
As I'm writing request specs to ensure the features won't be broken I decided to rather write separate Cucumber features. The nice thing is that I can use Capybara, and thanks to Selenium Web Drive, I can launch a server before I run my tests.
So, I created a dummy Sinatra application (that will represent the external service to which the actual code I'm testing is doing requests (including a nasty system('curl whatever.com')).
All I have to do is stub out the methods passed to curl to use Capybara.current_session.server.host and Capybara.current_session.server.port.
Once I'm done with my re-factoring all I have to do is remove the Capybara server variables, and Selenium web drive from the cucumber/capybara configuration.
Tests after a brief change will be still working and will be valid.
Update
In the end I wrote it all with RSpec request tests, as doing it in Cucumber was little bit time consuming and I already spend too much time on this.
I mark these kind of request tests with RSpec tag and Before I lunch these I manually lunch simple Sinatra/Grape dummy API application to which the request are made. (Then I run RSpec tests with this tag)
So basically I end up with specs for functionality that uses net/http that uses WebMock and don't need a server, and request tests for which I need to run the server before I run the specs. So the original question remains, how to lunch a server before tests start
After I cover all the functionality I'm gonig to rewrite the curl to net/http however I'm going to keep those requests specs as I discovered they are nice idea when it comes to crazy API scenarios (like testing https + diggested authentication)

How do I test a Curl based FaceBook API implementation?

I wrote my own FaceBook library that uses actual Curl requests, not libcurl.
Is there a way to test it? I'm asking this because most solutions involve using something like fakeweb which as far as I can tell will not work here.
The existing code can be found on my github page.
One approach would be to use a different host/port in test mode (eg localhost:12345)
Then in your test run a sinatra or webrick servlet on that port that you configure to respond to the requests your code should be making
You could mock Request.dispatcher with an expected behavior, pretty much like Fakeweb would do.
There are a few examples on this file, specially https://github.com/chrisk/fakeweb/blob/master/lib/fake_web/ext/net_http.rb#L44.
When running your tests/specs, monkey-patch the run method of your Request class to hook into the Marston VCR library. See the existing library_hooks subdir for examples and ideas on how to do this -- the fakeweb implementation is a good place to start.
VCR works well with live services like Facebook's because it captures interactions "as is", and VCRs can be easily re-recorded when the services change.
I'm running into problems with your library, however. You need to require the cgi and json libraries; it also looks like it requires a Rails environment (it's failing to find with_indifferent_access on Hash).

What's the best way to test application API library in Ruby?

Im developing a ruby API library for some web application (not rails based).
Library (in short overview) consists of the following objects:
Client - main api class
Request - module that handles all data transfers
Item (record) - object with attributes (result of api operations)
Im having a hard time figuring out whats the best way to test such libraries?
Currently using RSpec2 and actual (live) requests. But also might use fixtures.
Any suggestions?
You can use WebMock to mock requests. It has RSpec helpers to aid you in your tests.
I haven't personally used WebMock, but once used Fakeweb to accomplish a similar task. The only disadvantage of using mock requests is that if the remote code changes,

Resources