How to test Recurly.js in Ruby using RSpec, Capybara and Phantom.js
Everyone who developed a web application heard about the so called PCI-compliance. Briefly, it regulates the requirements your application must meet if it deals with billing details. It usually takes several months to go trough the process of approval, thus small and midsize companies prefer using hosted billing solutions. The most popular ones are Chargify, Braintree, Stripe and Recurly. We chose the last one for development of the subscriptions and the billing details submission on one of our current Forex Jingle.
Recurly offers Recurly.js, a great integrated solution that passes billing details directly to the Recurly server. Look at the interaction graph:
The app generates a page that contains a Recurly form.
The customer fills out and submits the form to Recurly directly.
Recurly responds with a token that the app needs for further interaction.
The form posts the token to the app.
We are used to testing things we build thoroughly. Each project has its own specific traits and Forex Jingle is no exception. Let's focus on the Recurly integration testing. Since Recurly.js depends on JavaScript, we have to use a real JavaScript-enabled browser during the tests. This requirement can be satisfied by a pretty standard bunch: RSpec + Capybara + Phantom.js.
As far as the application communicates with Recurly there are several API calls during the subscription process. It would take too much time to perform actual communications in each testing scenario, that is why we use the VCR gem perfect for this case. But look at the figure: there is a crossdomain JSONP-request initiated by the browser, not by the application server where the test suites work, thus these requests cannot be caught by the VCR or similar tools.
The only elegant solution we came up with is on-the-fly Recurly.js patching. After in-depth code review of the well-designed Recurly.js library, it wasn't hard to apply the following patch right before submitting the form:
# The original 'save' function performs JSONP request to Recurly. # A token is borrowed during the real API interaction. page.driver.execute_script(""" Â Recurly.Subscription.save = function (options) { Â Â Recurly.postResult('/subscription', { token: 'afc58c4895354255a422cc0405a045b0' }, options); Â } """)
As you can see, the code redefines an internal Recurly.js function that is in charge of sending the billing details to the Recurly server. Thus after this patch is applied, the function just posts a token back to your server. Don't forget to record a VCR cassette first to stub the server-side API-calls using your own token. The same thing could be done for Recurly's billing info update form.













