> For the complete documentation index, see [llms.txt](https://nicolasiensen.gitbook.io/vcr/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://nicolasiensen.gitbook.io/vcr/test-frameworks/cucumber.md).

# Usage With Cucumber

VCR can be used with cucumber in two basic ways:

* Use `VCR.use_cassette` in a step definition.
* Use a `VCR.cucumber_tags` block to tell VCR to use a cassette for a tagged scenario.

  In a cucumber support file (e.g. features/support/vcr.rb), put code like this:

  ```ruby
  VCR.cucumber_tags do |t|
  t.tag  '@tag1'
  t.tags '@tag2', '@tag3'

  t.tag  '@tag3', :cassette => :options
  t.tags '@tag4', '@tag5', :cassette => :options
  t.tag  '@vcr', :use_scenario_name => true
  end
  ```

  VCR will use a cassette named `cucumber_tags/<tag_name>` for scenarios with each of these tags (Unless the `:use_scenario_name` option is provided. See below). The configured `default_cassette_options` will be used, or you can override specific options by passing a hash as the last argument to `#tag` or `#tags`.

  You can also have VCR name your cassettes automatically according to the feature and scenario name by providing `:use_scenario_name => true` to `#tag` or `#tags`. In this case, the cassette will be named `<feature_name>/<scenario_name>`. For scenario outlines, VCR will record one cassette per row, and the cassettes will be named `<feature_name>/<scenario_name>/<row_name>`.

## Record HTTP interactions in a scenario by tagging it

*Given* a file named "lib/server.rb" with:

```
if ENV['WITH_SERVER'] == 'true'
  $server = start_sinatra_app do
    get('/:path') { "Hello #{params[:path]}" }
  end
end
```

*Given* a file named "features/support/vcr.rb" with:

```
require "lib/server"
require 'vcr'

VCR.configure do |c|
  c.hook_into :webmock
  c.cassette_library_dir     = 'features/cassettes'
  c.default_cassette_options = {
    :match_requests_on => [:method, :host, :path]
  }
end

VCR.cucumber_tags do |t|
  t.tag  '@localhost_request' # uses default record mode since no options are given
  t.tags '@disallowed_1', '@disallowed_2', :record => :none
  t.tag  '@vcr', :use_scenario_name => true
end
```

*And* a file named "features/step\_definitions/steps.rb" with:

```
require 'net/http'

When /^a request is made to "([^"]*)"$/ do |url|
  uri = URI.parse(url)
  uri.port = $server.port if $server
  @response = Net::HTTP.get_response(uri)
end

When /^(.*) within a cassette named "([^"]*)"$/ do |step_name, cassette_name|
  VCR.use_cassette(cassette_name) { step(step_name) }
end

Then /^the response should be "([^"]*)"$/ do |expected_response|
  expect(@response.body).to eq(expected_response)
end
```

*And* a file named "features/vcr\_example.feature" with:

```
Feature: VCR example

  Note: Cucumber treats the pre-amble as part of the feature name. When
  using the :use_scenario_name option, VCR will only use the first line
  of the feature name as the directory for the cassette.

  @localhost_request
  Scenario: tagged scenario
    When a request is made to "http://localhost:7777/localhost_request_1"
    Then the response should be "Hello localhost_request_1"
    When a request is made to "http://localhost:7777/nested_cassette" within a cassette named "nested_cassette"
    Then the response should be "Hello nested_cassette"
    When a request is made to "http://localhost:7777/localhost_request_2"
    Then the response should be "Hello localhost_request_2"

  @vcr
  Scenario: tagged scenario

  Note: Like the feature pre-amble, Cucumber treats the scenario pre-amble
  as part of the scenario name. When using the :use_scenario_name option,
  VCR will only use the first line of the feature name as the directory
  for the cassette.

    When a request is made to "http://localhost:7777/localhost_request_1"
    Then the response should be "Hello localhost_request_1"

  @vcr
  Scenario Outline: tagged scenario outline
    When a request is made to "http://localhost:7777/localhost_request_1"
    Then the response should be "Hello localhost_request_1"
    Examples:
      | key  | value |
      | foo  | bar   |

  @disallowed_1
  Scenario: tagged scenario
    When a request is made to "http://localhost:7777/allowed" within a cassette named "allowed"
    Then the response should be "Hello allowed"
    When a request is made to "http://localhost:7777/disallowed_1"

  @disallowed_2
  Scenario: tagged scenario
    When a request is made to "http://localhost:7777/disallowed_2"
```

*And* the directory "features/cassettes" does not exist

*When* I run `cucumber WITH_SERVER=true features/vcr_example.feature`

*Then* it should fail with "5 scenarios (2 failed, 3 passed)"

*And* the file "features/cassettes/cucumber\_tags/localhost\_request.yml" should contain "Hello localhost\_request\_1"

*And* the file "features/cassettes/cucumber\_tags/localhost\_request.yml" should contain "Hello localhost\_request\_2"

*And* the file "features/cassettes/nested\_cassette.yml" should contain "Hello nested\_cassette"

*And* the file "features/cassettes/allowed.yml" should contain "Hello allowed"

*And* the file "features/cassettes/VCR\_example/tagged\_scenario.yml" should contain "Hello localhost\_request\_1"

*And* the file "features/cassettes/VCR*example/tagged\_scenario\_outline/\_foo\_bar*.yml" should contain "Hello localhost\_request\_1"

*When* I run `cucumber features/vcr_example.feature`

*Then* it should fail with "5 scenarios (2 failed, 3 passed)"

*And* the output should contain each of the following:

\| An HTTP request has been made that VCR does not know how to handle: | | GET <http://localhost:7777/disallowed_1> | | An HTTP request has been made that VCR does not know how to handle: | | GET <http://localhost:7777/disallowed_2> |

*And* the file "features/cassettes/cucumber\_tags/localhost\_request.yml" should contain "Hello localhost\_request\_1"

*And* the file "features/cassettes/cucumber\_tags/localhost\_request.yml" should contain "Hello localhost\_request\_2"

*And* the file "features/cassettes/nested\_cassette.yml" should contain "Hello nested\_cassette"

*And* the file "features/cassettes/allowed.yml" should contain "Hello allowed"

*And* the file "features/cassettes/VCR\_example/tagged\_scenario.yml" should contain "Hello localhost\_request\_1"

*And* the file "features/cassettes/VCR*example/tagged\_scenario\_outline/\_foo\_bar*.yml" should contain "Hello localhost\_request\_1".

## `:allow_unused_http_interactions => false` does not raise if the scenario already failed

*Given* a previously recorded cassette file "features/cassettes/cucumber\_tags/example.yml" with:

```
--- 
http_interactions: 
- request: 
    method: get
    uri: http://example.com/foo
    body: 
      encoding: UTF-8
      string: ""
    headers: {}
  response: 
    status: 
      code: 200
      message: OK
    headers: 
      Content-Length: 
      - "5"
    body: 
      encoding: UTF-8
      string: Hello
    http_version: "1.1"
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
recorded_with: VCR 2.0.0
```

*And* a file named "features/support/vcr.rb" with:

```
require 'vcr'

VCR.configure do |c|
  c.hook_into :webmock
  c.cassette_library_dir = 'features/cassettes'
end

VCR.cucumber_tags do |t|
  t.tag '@example', :allow_unused_http_interactions => false
end
```

*And* a file named "features/step\_definitions/steps.rb" with:

```
When /^the scenario fails$/ do
  raise "boom"
end
```

*And* a file named "features/vcr\_example.feature" with:

```
Feature:

  @example
  Scenario: tagged scenario
    When the scenario fails
```

*When* I run `cucumber features/vcr_example.feature`

*Then* it should fail with "1 scenario (1 failed)"

*And* the output should contain "boom"

*And* the output should not contain "There are unused HTTP interactions".
