ruby-on-railsrubyrspeccapybaravcr

Run Specs With VCR without explicitly specifying the cassette name


I have capybara feature specs I intend running without explicitly specifying a cassette name. E.g:

  scenario "by searching via a title" do
    visit root_path

    fill_in "search", with: "cheddar"
    find(".search-btn").click


    expect(page).to have_content(/White Cheddar/)
  end
  scenario "by searching via a description" do
    visit root_path

    fill_in "search", with: "cheddar"
    select "Description", from: "search_field"
    find(".search-btn").click


    expect(page).to have_content(/White Cheddars Are Scarce/)
  end

Each of these specs goes out to hit a third party API. I want to use a different cassette name for each of these specs without having to explicitly use VCR.use_cassette. I want my feature specs to be clear and concise enough just focusing on the user's action. Is there a way to achieve this?


Solution

  • The way I have handled something like this in the past is by configuring it from within the rails_helper file.

    In your Rspec.configure block, you can retrieve details of each running spec and alter things either before, around or after the running of each spec example. That enabled me to have a nice DSL that allows me to specify the cassette name as a vcr tag. So in your case, it can become:

      scenario "by searching via a title", vcr: :search_title do
        visit root_path
    
        fill_in "search", with: "cheddar"
        find(".search-btn").click
    
    
        expect(page).to have_content(/White Cheddar/)
      end
    
      scenario "by searching via a description", vcr: :search_description do
        visit root_path
    
        fill_in "search", with: "cheddar"
        select "Description", from: "search_field"
        find(".search-btn").click
    
    
        expect(page).to have_content(/White Cheddars Are Scarce/)
      end
    

    The changes I had to do to make this work were within the rails_helper file:

    RSpec.configure do |c|
      c.around(:each, :vcr) do |example|
        name = Array(example.metadata.dig(:vcr)).join
        options = example.metadata.slice(:record, :match_requests_on)
        VCR.use_cassette(name, options) { example.call }
      end
    end
    

    For each spec example with a vcr tag, grab the spec's metadata and retrieve whatever is stored in the vcr tag as the cassette name. The rest of the lines just activates VCR for only specs having the VCR tag. You can see more of why I did this from this railscast episode