Introduction into SitePrism.Vcr

Posted: Oct 30, 2013

Last years we hear more and more about SOA (service oriented architecture). Actually, it is very naturally, because it gives you huge flexibility. Instead of coupling all functionality into one monolithic application we can spread functionality on a few different applications communicating with each other through API (REST, SOAP whatever). It is good decision in most cases. Lets say, you’ve started one big project on Ruby, but then you’ve found out that for one particular functionality it was a mistake to use Ruby, instead of rewriting a whole application you can easily rewrite that part from scratch on some other language if it makes sense. Also, sometimes we have old code base written on some language which we don’t want to use for our project anymore, we can wrap up such old code base into API and start creating a new version of a project on Ruby for example. Even if you spread your Ruby application onto a few smaller application, you will have issues with dependencies. Each small independent application can use own sets of libraries and you will have less issues with updating such dependencies since you can do it bit by bit for each application separately.

The project which we develop is separated onto 2 applications communicating through SOAP API. I guess it was a good idea and we have to spread it even more onto more independent applications providing public API. When we started developing another part of our application, we had started using SitePrism and Vcr, because we wanted to have much more clear integration tests, because we wanted to make sure our application is properly integrated with our API. After using such libraries for a few months we found out how it was difficult to use them together without kind of a bridge between them. Therefore, I started developing open source library which allows us to have better integration with such libraries. Its name is SitePrism.Vcr. I guess I have collected all features in the readme file of this project, but in this blog post I want to show a simple introduction to this library and why it may be interested for other developers.

Ok, lets start with installation.

Add the following line to your Gemfile:

gem 'site_prism.vcr'

Add following lines to your spec/spec_helper.rb:

VCR.configure do |c|
  c.cassette_library_dir = 'spec/fixtures'
end

All native options of VCR can be used in your project as usual, SitePrism.Vcr doesn’t eliminate you from using Vcr and it doesn’t try to hide it from you. If you need to specify additional options for VCR here (it may be some rules about ignoring request parameters whatever). It is better to check VCR documentation to make sure you are aware about all configuration options of VCR, maybe some of them will be useful for you.

Lets say our application should work with GitHub API (code example is here). The idea of this application is to:

For this purpose we have following code:

get '/info/:nickname' do |nickname|
  info = {
    repos: []
  }

  github = Github.new

  begin
    user_info = github.users.get(user: nickname)

    info[:user] = {
      name: user_info.name,
      location: user_info.location,
      email: user_info.email
    }

    github.repos.list(user: nickname) do |repo|
      info[:repos] << {
        url: repo.svn_url,
        watchers: repo.watchers
      }
    end

    content_type 'application/json'
    info.to_json
  rescue Github::Error::NotFound => error
    status 404
  end
end

As you can see here we work with 2 API calls. Since our application is modern we request this action through AJAX request. (you can check code here how it is requested).

We have a few cases which should be tested:

We start with describing elements on the page:

class MainPage < SitePrism::Page
  set_url '/'

  element :nickname_field, '#nickname' # input field for entering user's login
  element :loading_indicator, '#loading_indicator' # loading indicator to be shown while performing AJAX request

  element_with_vcr \ # submit button sending a request to the app
    :submit_btn,
    '#get_info' do
      home_path '/user' # specifies home path to cassettes

      path '~/', [
        'info',             # cassette to stub user's info
        'repositories' # cassette to stub repositories list of an user
      ]

      waiter &:wait_until_loading_indicator_invisible # waiter which keeps test execution until expectation is met
    end

  element :info_container, '#info' # container which is used for rendering user's info
end

It looks like a typical page class defined with SitePrism (please, check SitePrism documentation if you need more info). But, there is a method which you will not find in the documentation about site prism. SitePrism.Vcr gem provides element_with_vcr method which allows you to link SitePrism elements with Vcr cassettes. All options are defined in a block. SitePrism.Vcr provides own DSL for:

All tests are written and you can check them here.

The first test is about displaying user’s info:

context 'when there is a requested user' do
  before do
    @main_page.nickname_field.set 'nestd'
    @main_page.submit_btn.click_and_apply_vcr
  end

  it 'displays user\' info' do
    @main_page.info_container.should have_content('Dmitriy Nesteryuk')
    @main_page.info_container.should have_content('Zaporizhzhia, Ukraine')
  end
end

In this code you may have noticed a new method click_and_apply_vcr. This method actually does usual click on an element and then inserts cassettes specified for the submit_btn element in the page class (please, remember the element_with_vcr method). As you can see the test is very clear and simple. It is benefit of SitePrism.

Now, we have to check that repositories of an user are displayed as well. The test will be almost the same as the test about displaying user`s info:

before do
  @main_page.nickname_field.set 'nestd'
  @main_page.submit_btn.click_and_apply_vcr
end

# some other tests here

context 'when there are repositories' do
  it 'displays repositories of an user' do
    @main_page.info_container.should have_content('nestd/site_prism.vcr')
    @main_page.info_container.should have_content('nestd/site_prism.vcr_example')
  end
end

Ok, now we have a bit more complicated situation. We have to write a test when an user has no repositories.

context 'when there are repositories' do
  before do
    @main_page.submit_btn.click_and_apply_vcr do
      exchange '~/repositories', '~/no_repositories'
    end
  end

  it 'displays a message about empty repositories' do
    @main_page.info_container.should have_content('This user has no repositories')
  end
end

To do that, we have passed a block to the click_and_apply_vcr method. That block allows you to adjust list of cassettes which should be used while running test. In this block you see that we have used the exchange method. This method allows you to swap a default cassette (or a list of cassettes) on some another to change a response from external API. It is very useful when you need your test to use default cassettes, but only one cassette should differ.

And the last case which we have to test is a case which allows you to simulate situation when there is no requested user.

context 'when there is not a requested user' do
  before do
    @main_page.nickname_field.set 'rewwwwwwwww'
    @main_page.submit_btn.click_and_apply_vcr do
      fixtures ['~/no_user']
    end
  end

  it 'displays a message about no user' do
    @main_page.info_container.should have_content('Error: Sorry, but the requested user is not found')
  end
end

In this case we have used the fixtures method which allows us to override default cassettes. It means once you have used the fixtures or the path helper method in the adjusting block, the default fixtures won’t be applied at all. In this specific test we just specified a cassette which will simulate 404 response from Github which is sent when an user is not found.

SitePrism.Vcr has some more additional helper methods and it allows you even specify fixtures for page loading. Please, take a look at the documentation of this gem and may be you will find it useful.

Hey, do you need to host your project? Just click here and get $10 in credit from DigitalOcean.