Title: | Record 'HTTP' Calls to Disk |
---|---|
Description: | Record test suite 'HTTP' requests and replays them during future runs. A port of the Ruby gem of the same name (<https://github.com/vcr/vcr/>). Works by hooking into the 'webmockr' R package for matching 'HTTP' requests by various rules ('HTTP' method, 'URL', query parameters, headers, body, etc.), and then caching real 'HTTP' responses on disk in 'cassettes'. Subsequent 'HTTP' requests matching any previous requests in the same 'cassette' use a cached 'HTTP' response. |
Authors: | Scott Chamberlain [aut, cre] (ORCID: <https://orcid.org/0000-0003-1444-9135>), Aaron Wolen [aut] (ORCID: <https://orcid.org/0000-0003-2542-2202>), Maëlle Salmon [aut] (ORCID: <https://orcid.org/0000-0002-2815-0399>), Daniel Possenriede [aut] (ORCID: <https://orcid.org/0000-0002-6738-9845>), Hadley Wickham [aut], rOpenSci [fnd] (ROR: <https://ror.org/019jywm96>) |
Maintainer: | Scott Chamberlain <[email protected]> |
License: | MIT + file LICENSE |
Version: | 1.7.0.91 |
Built: | 2025-05-29 17:22:02 UTC |
Source: | https://github.com/ropensci/vcr |
List cassettes, get current cassette, etc.
cassettes() current_cassette() current_cassette_recording() current_cassette_replaying() cassette_path()
cassettes() current_cassette() current_cassette_recording() current_cassette_replaying() cassette_path()
cassettes()
: returns all active cassettes in the current
session.
current_cassette()
: returns NULL
when no cassettes are in use;
returns the current cassette (a Cassette
object) when one is in use
currrent_cassette_recording()
and current_cassette_replaying()
:
tell you if the current cassette is recording and/or replaying. They
both return FALSE
if there is no cassette in use.
cassette_path()
: returns the current directory path where cassettes
will be stored
vcr_configure(dir = tempdir()) # list all cassettes cassettes() # list the currently active cassette insert_cassette("stuffthings") current_cassette() cassettes() eject_cassette() cassettes() # list the path to cassettes cassette_path() vcr_configure(dir = file.path(tempdir(), "foo")) cassette_path() vcr_configure_reset()
vcr_configure(dir = tempdir()) # list all cassettes cassettes() # list the currently active cassette insert_cassette("stuffthings") current_cassette() cassettes() eject_cassette() cassettes() # list the path to cassettes cassette_path() vcr_configure(dir = file.path(tempdir(), "foo")) cassette_path() vcr_configure_reset()
insert_example_cassette()
is a wrapper around insert_cassette()
that
stores cassettes in inst/_vcr/
. Call it in the first line of your examples
(typically wrapped in \dontshow{}
), and call eject_cassette()
on the
last line.
Run the example manually once to record the vignettte, then it will be
replayed during R CMD check
, ensuring that your example no longer uses
the internet.
insert_example_cassette( name, package, record = NULL, match_requests_on = NULL, serialize_with = NULL, preserve_exact_body_bytes = NULL, re_record_interval = NULL )
insert_example_cassette( name, package, record = NULL, match_requests_on = NULL, serialize_with = NULL, preserve_exact_body_bytes = NULL, re_record_interval = NULL )
name |
The name of the cassette. This is used to name a file on disk, so it must be valid file name. |
package |
Package name. |
record |
Record mode. This will be |
match_requests_on |
Character vector of request matchers used to determine which recorded HTTP interaction to replay. Possible values are:
If more than one is specified, all components must match in order for the
request to match. If not supplied, defaults to Note that the request header and body will only be included in the
cassette if |
serialize_with |
(string) Which serializer to use:
|
preserve_exact_body_bytes |
(logical) Force a binary (base64)
representation of the request and response bodies? By default, vcr
will look at the |
re_record_interval |
(integer) How frequently (in seconds) the
cassette should be re-recorded. Default: |
# In this example I'm showing the insert and eject commands, but you'd # usually wrap these in \dontshow{} so the user doesn't see them and # think that they're something they need to copy. insert_example_cassette("httpbin-get", package = "vcr") req <- httr2::request("https://hb.cran.dev/get") resp <- httr2::req_perform(req) str(httr2::resp_body_json(resp)) eject_cassette()
# In this example I'm showing the insert and eject commands, but you'd # usually wrap these in \dontshow{} so the user doesn't see them and # think that they're something they need to copy. insert_example_cassette("httpbin-get", package = "vcr") req <- httr2::request("https://hb.cran.dev/get") resp <- httr2::req_perform(req) str(httr2::resp_body_json(resp)) eject_cassette()
turn_on()
and turn_off()
turn on and off for the whole session.
turned_off(code)
temporarily turns off while code
is running,
guaranteeing that you make a real HTTP request.
turned_on()
reports on if vcr is turned on or not.
skip_if_vcr_off()
skips a test if vcr is turned off. This is
occasionally useful if you're using a cassette to simulate a faked
request, or if the real request would return different values (e.g.
you're testing date parsing and the request returns the current date).
You can also control the default behaviour in a new session by setting the following environment variables before R starts:
Use VCR_TURN_OFF=true
to suppress all vcr usage, ignoring all
cassettes. This is useful for CI/CD workflows where you want to ensure
the test suite is run against the live API.
Set VCR_TURNED_OFF=true
to turn off vcr, but still use cassettes.
turn_on() turn_off(ignore_cassettes = FALSE) turned_off(code, ignore_cassettes = FALSE) turned_on() skip_if_vcr_off()
turn_on() turn_off(ignore_cassettes = FALSE) turned_off(code, ignore_cassettes = FALSE) turned_on() skip_if_vcr_off()
ignore_cassettes |
(logical) Controls what happens when a cassette is
inserted while vcr is turned off. If |
code |
Any block of code to run, presumably an HTTP request. |
# By default, vcr is turned on turned_on() # you can turn off for the rest of the session turn_off() turned_on() # turn on again turn_on() # or just turn it on turn off temporarily turned_off({ # some HTTP requests here turned_on() })
# By default, vcr is turned on turned_on() # you can turn off for the rest of the session turn_off() turned_on() # turn on again turn_on() # or just turn it on turn off temporarily turned_off({ # some HTTP requests here turned_on() })
setup_knitr()
registers a knitr hook to make it easy to use vcr inside a
vignette. First call setup_knitr()
in your setup chunk (or other chunk
early in the document):
```{r setup} #| include: false vcr::setup_knitr() ```
Then, in a chunk where you want to use a cassette, set the cassette
chunk
option to the name of the cassette:
```{r} #| cassette: name req <- httr2::request("http://r-project.org") resp <- httr2::req_perform(req) ```
setup_knitr(prefix = NULL, dir = "_vcr", ...)
setup_knitr(prefix = NULL, dir = "_vcr", ...)
prefix |
An prefix for the cassette name to make cassettes unique across vignettes. Defaults to the file name (without extension) of the currently executing vignette. |
dir |
Directory where to create the cassette file. Default: '"_vcr"“. |
... |
Other arguments passed on to |
use_cassette(...)
uses a cassette for the code in ...
,
local_cassette()
uses a cassette for the current function scope (e.g.
for one test).
use_cassette( name, ..., dir = NULL, record = NULL, match_requests_on = NULL, serialize_with = NULL, preserve_exact_body_bytes = NULL, re_record_interval = NULL, warn_on_empty = NULL ) local_cassette( name, dir = NULL, record = NULL, match_requests_on = NULL, serialize_with = NULL, preserve_exact_body_bytes = NULL, re_record_interval = NULL, warn_on_empty = NULL, frame = parent.frame() )
use_cassette( name, ..., dir = NULL, record = NULL, match_requests_on = NULL, serialize_with = NULL, preserve_exact_body_bytes = NULL, re_record_interval = NULL, warn_on_empty = NULL ) local_cassette( name, dir = NULL, record = NULL, match_requests_on = NULL, serialize_with = NULL, preserve_exact_body_bytes = NULL, re_record_interval = NULL, warn_on_empty = NULL, frame = parent.frame() )
name |
The name of the cassette. This is used to name a file on disk, so it must be valid file name. |
... |
a block of code containing one or more requests (required). Use
curly braces to encapsulate multi-line code blocks. If you can't pass a code
block use |
dir |
The directory where the cassette will be stored. If unspecified,
(and hasn't been set in |
record |
Record mode that dictates how HTTP requests/responses are recorded. Possible values are:
|
match_requests_on |
Character vector of request matchers used to determine which recorded HTTP interaction to replay. Possible values are:
If more than one is specified, all components must match in order for the
request to match. If not supplied, defaults to Note that the request header and body will only be included in the
cassette if |
serialize_with |
(string) Which serializer to use:
|
preserve_exact_body_bytes |
(logical) Force a binary (base64)
representation of the request and response bodies? By default, vcr
will look at the |
re_record_interval |
(integer) How frequently (in seconds) the
cassette should be re-recorded. Default: |
warn_on_empty |
(logical) Warn if the cassette is ejected but no interactions
have been recorded. Default: |
frame |
Attach exit handlers to this environment. Typically, this
should be either the current environment or a parent frame (accessed
through |
an object of class Cassette
Default values for arguments controlling cassette behavior are
inherited from vcr's global configuration. See vcr_configure()
for a
complete list of options and their default settings. You can override these
options for a specific cassette by changing an argument's value to something
other than NULL
when calling either insert_cassette()
or
use_cassette()
.
This function handles a few different scenarios:
when everything runs smoothly, and we return a Cassette
class object
so you can inspect the cassette, and the cassette is ejected
when there is an invalid parameter input on cassette creation, we fail with a useful message, we don't return a cassette, and the cassette is ejected
when there is an error in calling your passed in code block,
we return with a useful message, and since we use on.exit()
the cassette is still ejected even though there was an error,
but you don't get an object back
whenever an empty cassette (a yml/json file) is found, we delete it
before returning from the use_cassette()
function call. we achieve
this via use of on.exit()
so an empty cassette is deleted even
if there was an error in the code block you passed in
Note that "eject" only means that the R session cassette is no longer in use. If any interactions were recorded to disk, then there is a file on disk with those interactions.
There's a few ways to get correct line numbers for failed tests and one way to not get correct line numbers:
Correct: Either wrap your test_that()
block inside your use_cassette()
block, OR if you put your use_cassette()
block inside your test_that()
block put your testthat
expectations outside of the use_cassette()
block.
Incorrect: By wrapping the use_cassette()
block inside your
test_that()
block with your testthat expectations inside the
use_cassette()
block, you'll only get the line number that the
use_cassette()
block starts on.
insert_cassette()
and eject_cassette()
for the underlying
functions.
## Not run: library(vcr) library(crul) vcr_configure(dir = tempdir()) use_cassette(name = "apple7", { cli <- HttpClient$new(url = "https://hb.opencpu.org") resp <- cli$get("get") }) readLines(file.path(tempdir(), "apple7.yml")) # preserve exact body bytes - records in base64 encoding use_cassette("things4", { cli <- crul::HttpClient$new(url = "https://hb.opencpu.org") bbb <- cli$get("get") }, preserve_exact_body_bytes = TRUE) ## see the body string value in the output here readLines(file.path(tempdir(), "things4.yml")) # cleanup unlink(file.path(tempdir(), c("things4.yml", "apple7.yml"))) # with httr library(vcr) library(httr) vcr_configure(dir = tempdir(), log = TRUE, log_opts = list(file = file.path(tempdir(), "vcr.log"))) use_cassette(name = "stuff350", { res <- GET("https://hb.opencpu.org/get") }) readLines(file.path(tempdir(), "stuff350.yml")) use_cassette(name = "catfact456", { res <- GET("https://catfact.ninja/fact") }) # record mode: none library(crul) vcr_configure(dir = tempdir()) ## make a connection first conn <- crul::HttpClient$new("https://eu.httpbin.org") ## this errors because 'none' disallows any new requests # use_cassette("none_eg", (res2 <- conn$get("get")), record = "none") ## first use record mode 'once' to record to a cassette one <- use_cassette("none_eg", (res <- conn$get("get")), record = "once") one; res ## then use record mode 'none' to see its behavior two <- use_cassette("none_eg", (res2 <- conn$get("get")), record = "none") two; res2 ## End(Not run)
## Not run: library(vcr) library(crul) vcr_configure(dir = tempdir()) use_cassette(name = "apple7", { cli <- HttpClient$new(url = "https://hb.opencpu.org") resp <- cli$get("get") }) readLines(file.path(tempdir(), "apple7.yml")) # preserve exact body bytes - records in base64 encoding use_cassette("things4", { cli <- crul::HttpClient$new(url = "https://hb.opencpu.org") bbb <- cli$get("get") }, preserve_exact_body_bytes = TRUE) ## see the body string value in the output here readLines(file.path(tempdir(), "things4.yml")) # cleanup unlink(file.path(tempdir(), c("things4.yml", "apple7.yml"))) # with httr library(vcr) library(httr) vcr_configure(dir = tempdir(), log = TRUE, log_opts = list(file = file.path(tempdir(), "vcr.log"))) use_cassette(name = "stuff350", { res <- GET("https://hb.opencpu.org/get") }) readLines(file.path(tempdir(), "stuff350.yml")) use_cassette(name = "catfact456", { res <- GET("https://catfact.ninja/fact") }) # record mode: none library(crul) vcr_configure(dir = tempdir()) ## make a connection first conn <- crul::HttpClient$new("https://eu.httpbin.org") ## this errors because 'none' disallows any new requests # use_cassette("none_eg", (res2 <- conn$get("get")), record = "none") ## first use record mode 'once' to record to a cassette one <- use_cassette("none_eg", (res <- conn$get("get")), record = "once") one; res ## then use record mode 'none' to see its behavior two <- use_cassette("none_eg", (res2 <- conn$get("get")), record = "none") two; res2 ## End(Not run)
Configurable options that define vcr's default behavior.
vcr_configure( dir, record, match_requests_on, serialize_with, json_pretty, ignore_hosts, ignore_localhost, ignore_request, preserve_exact_body_bytes, turned_off, re_record_interval, log, log_opts, filter_sensitive_data, filter_sensitive_data_regex, filter_request_headers, filter_response_headers, filter_query_parameters, write_disk_path, warn_on_empty_cassette ) local_vcr_configure(..., .frame = parent.frame()) vcr_configure_reset() vcr_configuration() vcr_config_defaults()
vcr_configure( dir, record, match_requests_on, serialize_with, json_pretty, ignore_hosts, ignore_localhost, ignore_request, preserve_exact_body_bytes, turned_off, re_record_interval, log, log_opts, filter_sensitive_data, filter_sensitive_data_regex, filter_request_headers, filter_response_headers, filter_query_parameters, write_disk_path, warn_on_empty_cassette ) local_vcr_configure(..., .frame = parent.frame()) vcr_configure_reset() vcr_configuration() vcr_config_defaults()
dir |
Directory where cassettes are stored. |
record |
Record mode that dictates how HTTP requests/responses are recorded. Possible values are:
|
match_requests_on |
Character vector of request matchers used to determine which recorded HTTP interaction to replay. Possible values are:
If more than one is specified, all components must match in order for the
request to match. If not supplied, defaults to Note that the request header and body will only be included in the
cassette if |
serialize_with |
(string) Which serializer to use:
|
json_pretty |
(logical) want JSON to be newline separated to be easier
to read? Or remove newlines to save disk space? default: |
ignore_hosts |
(character) Vector of hosts to ignore. e.g.,
|
ignore_localhost |
(logical) Default: |
ignore_request |
List of requests to ignore. NOT USED RIGHT NOW, sorry |
preserve_exact_body_bytes |
(logical) Force a binary (base64)
representation of the request and response bodies? By default, vcr
will look at the |
turned_off |
(logical) VCR is turned on by default. Default:
|
re_record_interval |
(integer) How frequently (in seconds) the
cassette should be re-recorded. Default: |
log , log_opts
|
See |
filter_sensitive_data |
instructing vcr with what value to replace the real value of the query parameter. |
filter_sensitive_data_regex |
named list of values to replace. Follows
|
filter_request_headers |
(character/list) request headers to filter. A character vector of request headers to remove - the headers will not be recorded to disk. Alternatively, a named list similar to |
filter_response_headers |
(character/list) response headers to filter.
A character vector of response headers to remove - the headers will not be
recorded to disk. Alternatively, a named list similar to
|
filter_query_parameters |
(named list) query parameters to filter. A character vector of query parameters to remove - the query parameters will not be recorded to disk. Alternatively, a named list similar to |
write_disk_path |
(character) path to write files to
for any requests that write responses to disk. By default this will be
|
warn_on_empty_cassette |
(logical) Should a warning be thrown when an
empty cassette is detected? Empty cassettes are cleaned up (deleted) either
way. This option only determines whether a warning is thrown or not.
Default: |
... |
Configuration settings used to override defaults. |
.frame |
Attach exit handlers to this environment. Typically, this
should be either the current environment or a parent frame (accessed
through |
vcr_configure(dir = tempdir()) vcr_configure(dir = tempdir(), record = "all") vcr_configuration() vcr_config_defaults() vcr_configure(dir = tempdir(), ignore_hosts = "google.com") vcr_configure(dir = tempdir(), ignore_localhost = TRUE) # filter sensitive data vcr_configure(dir = tempdir(), filter_sensitive_data = list(foo = "<bar>") ) vcr_configure(dir = tempdir(), filter_sensitive_data = list(foo = "<bar>", hello = "<world>") )
vcr_configure(dir = tempdir()) vcr_configure(dir = tempdir(), record = "all") vcr_configuration() vcr_config_defaults() vcr_configure(dir = tempdir(), ignore_hosts = "google.com") vcr_configure(dir = tempdir(), ignore_localhost = TRUE) # filter sensitive data vcr_configure(dir = tempdir(), filter_sensitive_data = list(foo = "<bar>") ) vcr_configure(dir = tempdir(), filter_sensitive_data = list(foo = "<bar>", hello = "<world>") )
By default, logging is disabled, but you can easily enable for the
entire session with vcr_configure_log()
or for just one test with
local_vcr_configure_log()
.
vcr_configure_log( log = TRUE, file = stderr(), include_date = NULL, log_prefix = "Cassette" ) local_vcr_configure_log( log = TRUE, file = stderr(), include_date = NULL, log_prefix = "Cassette", frame = parent.frame() )
vcr_configure_log( log = TRUE, file = stderr(), include_date = NULL, log_prefix = "Cassette" ) local_vcr_configure_log( log = TRUE, file = stderr(), include_date = NULL, log_prefix = "Cassette", frame = parent.frame() )
log |
Should we log important vcr things? |
file |
A path or connection to log to |
include_date |
(boolean) Include date and time in each log entry. |
log_prefix |
"Cassette". We insert the cassette name after this prefix, followed by the rest of the message. |
frame |
Attach exit handlers to this environment. Typically, this
should be either the current environment or a parent frame (accessed
through |
# The default logs to stderr() vcr_configure_log() # But you might want to log to a file vcr_configure_log(file = file.path(tempdir(), "vcr.log"))
# The default logs to stderr() vcr_configure_log() # But you might want to log to a file vcr_configure_log(file = file.path(tempdir(), "vcr.log"))
When debugging, it's often useful to see the last request and response
respectively. These functions give you what would have been recorded to disk
or replayed from disk. If the last request wasn't recorded, and there was
no matching request, vcr_last_response
will return NULL
.
vcr_last_request() vcr_last_response()
vcr_last_request() vcr_last_response()
This function, similar to testthat::test_path()
, is designed to work both
interactively and during tests, locating files in the tests/
directory.
vcr_test_path(...)
vcr_test_path(...)
... |
Character vectors giving path components. Each character string
gets added to the path, e.g., |
A character vector giving the path
vcr_test_path()
assumes you are using testthat for your unit tests.
if (interactive()) { vcr_test_path("fixtures") }
if (interactive()) { vcr_test_path("fixtures") }