jjjjjjjj
jjjjjjjj

Reputation: 4503

Using multiple cassettes with VCR in one test

I am using VCR to record http interactions with an external API. This is my (working) code:

it 'does xyz....' do
    hook_payload = {ruby_hash: 'here'}

    VCR.use_cassette('my_folder/create_project') do
      VCR.use_cassette('my_folder/get_project') do
        update = Update.new(hook_payload)
        expect { update.call }.to change { Projects.count }.by(1)
      end
    end
  end

The code above works, but the organization isn't good, as I prefer to have the expect{} call outside the block. So, I tried this, but the following code does not work:

context 'my context', vcr: { group: 'my_folder', cassettes: %w[create_project get_project] } do
    it 'does xyz....' do
        hook_payload = {ruby_hash: 'here'}

        update = Update.new(hook_payload)
        expect { update.call }.to change { Projects.count }.by(1)
      end

However this code doesn't work and I get the following error:

VCR is currently using the following cassette: - /Users/me/this_project/spec/fixtures/vcr/my_folder/create_project.yml.

Under the current configuration VCR can not find a suitable HTTP interaction to replay and is prevented from recording new requests.

I am 100% sure that my_folder/get_project.yml is valid, and it works in other tests in the project.

I even put the cassettes (%w[create_project get_project]) in the same order that they are used in my code. What am I doing incorrectly here?

Upvotes: 15

Views: 6748

Answers (1)

Rimian
Rimian

Reputation: 38428

It's recommended to use the block but there are options if you don't want to do that. There are two ways: use an around hook or a before and an after hook.

If you load cassettes manually, you'll need to eject them if you reuse cassettes between tests as they don't like being loaded twice (the VCR analogy holds well here!).

https://www.rubydoc.info/github/vcr/vcr/VCR:insert_cassette

Try using VCR.insert_cassette which does not require a block. You'll need to call eject_cassette in your tear downs. I tried it and it worked. The ordering doesn't matter.

it 'does xyz....' do
  hook_payload = {ruby_hash: 'here'}

  VCR.insert_cassette('my_folder/create_project')
  VCR.insert_cassette('my_folder/get_project')
    
  update = Update.new(hook_payload)
    
  expect { update.call }.to change { Projects.count }.by(1)
end

Call eject to avoid loading cassettes twice:


VCR.eject_cassette(name: 'my_folder/create_project')
VCR.eject_cassette(name: 'my_folder/get_project')

The around hook might work for you too:

around do |example|
  cassettes = [
    { name: 'my_folder/create_project' },
    { name: 'my_folder/get_project' }
  ]
  VCR.use_cassettes cassettes do
    example.run
  end
end

You can even combine this with cassette config:

it 'whateva', vcr: { cassette_name: 'load another' } do

end

Upvotes: 5

Related Questions