Search code examples
rubyrspecyamlerbvcr

how do I dynamically generate multiple HTTP mock responses with VCR for Ruby/RSpec?


I'm hitting an API and for each request, there was a recorded request/response in the cassette YAML file. However, the only difference between the requests was the id in the query parameters.

How do I shrink my YAML file so that URLs are dynamically generated for each request?


Solution

  • You can use Dynamic ERB Cassettes with VCR, you just have to pass in the :erb option which can have a value of true or a hash containing the template variables to be passed to the cassette:

    ids = [0, 1, 2, 3]
    VCR.use_cassette('dynamic_generated_requests', :erb => { :ids => ids }) do
      # Make HTTP Requests
    end
    

    YAML File with ERB

    And your YAML file would look like this:

    ---
    http_interactions:
    <% ids.each do |id| %>
    - request:
        method: post
        uri: https://api.example.com/path/to/rest_api/<%= id %>/method
        body:
          encoding: UTF-8
        headers:
          content-type:
          - application/json
      response:
        status:
          code: 200
          message: OK
        headers:
          cache-control:
          - no-cache, no-store
          content-type:
          - application/json
          connection:
          - Close
        body:
          encoding: UTF-8
          string: '{"status_code": <%= id %>}'
        http_version: '1.1'
      recorded_at: Tue, 15 Jan 2019 16:14:14 GMT
    <% end %>
    recorded_with: VCR 3.0.0
    

    Note: the .yml file extension is still used because VCR handles the ERB processing through the :erb option.

    Debugging: raw_cassette_bytes

    If you want to debug this and make sure the YAML file looks good, you can print out the rendered YAML file with the raw_cassette_bytes method:

    puts VCR.current_cassette.send(:raw_cassette_bytes)
    

    Use that within the VCR.use_cassette block:

    VCR.use_cassette('dynamic_generated_requests', :erb => { :ids => ids }) do
      puts VCR.current_cassette.send(:raw_cassette_bytes)
      # Make HTTP Requests
    end