3

I have a Rails 4 app that uses a custom authentication gem that authenticates users against a third-party API. The app requires authentication for most actions on the site (visitors can do very little).

I am trying to use VCR to record the api request made during authentication for all of the integration tests, but all examples that I can find on SO and the Relish documentation only cover how to do this with Rspec in a 'describe do' spec, as referenced here:

https://www.relishapp.com/vcr/vcr/v/1-6-0/docs/test-frameworks/usage-with-rspec

Since no customers are involved on this project, I am writing integration tests with Rspec and Capybara instead of Cucumber, so my tests are using the 'feature/scenario' format like so:

feature 'posts' do
  scenario 'a user can log in' do
    # use vcr for api request
    sign_in_user # refers to a method that handles the api call to log in a user, which is what I would like VCR to record.
    expect(page).to have_content("User signed in successfully")
  end
end

Using the command described in the documentation:

use_vcr_cassette

inside of the 'scenario' block, returns an error:

Failure/Error: use_vcr_cassette

undefined local variable or method `use_vcr_cassette' for #<RSpec::ExampleGroups::Posts:0x007fb858369c38>

I followed the documentation to setup VCR in my spec/rails_helper.rb (which is included by the spec/spec_helper.rb)... which basically looks like this:

require 'vcr'
VCR.configure do |c|
  c.cassette_library_dir = 'support/vcr_cassettes'
  c.hook_into :webmock
end

Obviously added gem 'vcr' to my Gemfile development/test group and it is a thing in console and binding.pry from inside of a test.

Has anyone used VCR inside of a Rspec feature? or have any suggestions on what I might do as a workaround?

Thanks in advance

johndavid400
  • 1,552
  • 13
  • 15
  • That is a very outdated version of VCR which I'm guessing isn't what bundler pulled down. Take a look at the newer examples here: https://www.relishapp.com/vcr/vcr/v/2-9-3/docs – Anthony Mar 09 '15 at 23:38
  • 1
    I didn't set up VCR, but our tests have this: `feature 'posts', :vcr do` (and there's some config)... but that just automatically creates VCR cassettes named after the spec+scenario – Taryn East Mar 09 '15 at 23:48
  • This looks like it might be what we've got for our system: http://www.shaunambrose.com/2012/03/19/automatic-vcr-cassette-naming-for-rspec-and-cucumber/ – Taryn East Mar 10 '15 at 04:09
  • Thanks Taryn, that was mostly what I was looking for. In the link you posted, he added some stuff that is now deprecated, but I posted an answer with what worked for me. – johndavid400 Mar 10 '15 at 16:45

1 Answers1

5

Solution: Taryn East got me to the solution, but it is slightly different than the link posted for anyone trying to do this moving forward.

here is the most basic config in spec/rails_helper.rb or spec/spec_helper.rb:

require 'vcr'
VCR.configure do |c|
    c.cassette_library_dir = 'spec/cassettes'
    c.hook_into :webmock
    c.configure_rspec_metadata!
end

using c.configure_rspec_metadata! is required for Rspec to handle the :vcr tag.

And in an Rspec Feature spec:

feature 'users' do
  scenario 'logged in users should be able to do stuff', :vcr do
    # authenticate user or make other http request here 
  end
end

Oddly enough, in my tests - VCR is recording the response and if passes the first time, but fails the second time. I traced this to the response being stored differently than it is received.

On a normal request (using excon) like so:

resp = Excon.post(url, :body => data, :headers => { "Content-Type" => "application/x-www-form-urlencoded", "Authorization" => authorization_header })

The response has a header that is accessible in this format:

resp.headers["oauth_token"]

which returns an oauth token.

In the VCR response, it is being stored differently and only accessible as:

resp.headers["Oauth-Token"]

Which is weird, but workable. This may be a bug with VCR or some issue with Excon... too busy to figure that one out right now, but just a heads up in case anyone else uses this setup and gets a passing test with the live http request and a failing test when using the VCR cassette. A quick workaround is to either change the VCR cassette data to match what your code expects, or modify your code to accept either available value.

johndavid400
  • 1,552
  • 13
  • 15