Manipulating External Browser Requests When Testing
By: Josiah Anjos

If you’ve gotten deep into a Javascript-heavy Rails app lately, you might have noticed that the requests your driver makes during a Cucumber test are not mocked.  WebMock makes sure that your controllers aren’t making calls to external endpoints, but an often overlooked component is the driver itself (in our case capybara-webkit), which still makes calls via Javascript to external endpoints.

This obviously becomes is an issue, as we’d want our test suite to have as little external dependencies as possible.

During our research of selecting tools, we considered puffing-billy and SquidMan.

Puffing Billy

Puffing Billy

Puffing-billy is a very robust and powerful solution, because it allows you to manipulate the responses of requests, similar to how you would stub requests in RSpec or WebMock.  It is as simple as:

 if 'should stub google' do  
   proxy.stub('').and_return(:text => "I'm not Google!")  
   visit ''  
   page.should have_content("I'm not Google!")  

So you have the ability to craft responses for your actual browser, and remove those external calls.



SquidMan is a proxy server for OSX, that you can spin up, and set rules about where a specific host can make calls to.  Our configuration for this is that we set up a local squid instance, pointing to a specific port, and then we run our Cucumber tests configured with:

 driver.browser.set_proxy(host: '', port: 4404)

What this accomplishes, is that all of our http calls made go through SquidMan, so we can restrict or enable certain calls in our SquidMan configuration, in our case, we found it best to just restrict all but localhost.

What We Learned

At one point, we had an alpha version of our testing suite working with puffing-billy, but there were complications in running multiple EventMachine instances along side with something as simple as requiring WebMock for certain aspects of our tests.

According to the original and main contributor to puffing-billy, WebMock and puffing-billy weren’t really built to work with each other.  The general idea is that if you use puffing-billy, you need to let WebMock allow all connections, which is what we were trying to avoid. See this GitHub issue for some banter about the topic:

Seeing that our task of making our tests independent of external requests was falling a bit into over-engineering, we decided to take a step back, and look at what puffing-billy was in its essence.  And that was, simply put, a complex proxy server to serve crafted requests back to your browser.

Once we realized that the tests needed to be independent of those external requests, we decided to spin up a local Squid proxy server, that our capybara-webkit driver would point to during it’s runs locally, and on Travis CI.  And in our use case, we essentially made it so that any request made from to a specific ip/port, would have an empty response.

The technical side of this, prefaced in the SquidMan section above, is that whenever we ran Cucumber, our tests ran on localhost, so in the Squid cfg, we whitelisted localhost, and any request that Cucumber would make to a non- IP would return an empty response.

In terms of our acceptance tests, the requests that were made by the browser on almost every acceptance test were now immediately returned as empty, and it sped up our suite quite significantly… ~10% faster on the Cucumber side of things.  And we got rid of the flickering issues we would see sometimes, when our pages had external front-end Javascript popups.  Like guides on how to set something up, that were always loaded previously, and would sometimes block the flow, e.g. trying to click on a specific div, but the ad would popup in front of it.

Take these solutions with a grain of salt.  While we might want to return empty responses, because we don’t want to be checking if tracking is working every single time we visit a page during our test suite, others may want actual responses.  The puffing-billy gem isn’t widely adopted (yet), but it is very powerful, and there are a few collaborators there to answer questions frequently.


Meet Josiah:
Josiah is a Software Engineer at WeddingWire.