tests/testthat/test-request_handler-httr.R

skip_on_cran()

test_that("RequestHandlerHttr: httr", {
  local_vcr_configure(dir = withr::local_tempdir())
  skip_if_not_installed("xml2")

  load("httr_obj.rda")
  x <- RequestHandlerHttr$new(httr_obj)
  expect_s3_class(x, "RequestHandlerHttr")

  # do request
  local_cassette("greencow", warn_on_empty = FALSE)
  response <- x$handle()

  expect_s3_class(response, "response")
  # status code is correct
  expect_equal(response$status_code, 404)
})

test_that("httr status code works", {
  local_vcr_configure(dir = withr::local_tempdir())
  skip_if_not_installed("xml2")

  load("httr_obj.rda")

  expect_s3_class(httr_obj, "request")

  x <- RequestHandlerHttr$new(httr_obj)
  expect_s3_class(x, "RequestHandlerHttr")

  # do request
  use_cassette("greencow", response <- x$handle())
  expect_s3_class(response, "response")
  # status code is correct
  expect_equal(response$status_code, 404)

  # call again
  use_cassette("greencow", response2 <- x$handle())
  expect_s3_class(response2, "response")
  # status code is correct
  expect_equal(response2$status_code, 404)
})

test_that('issue 249 is correctly handled.', {
  local_vcr_configure(dir = withr::local_tempdir())

  use_cassette('get_401', {
    res <- httr::GET(hb('/status/401'))
  })
  expect_true(res$status_code == 401)
})

test_that("can ignore a request", {
  local_vcr_configure(
    dir = withr::local_tempdir(),
    ignore_localhost = TRUE,
    warn_on_empty_cassette = FALSE
  )

  use_cassette("test", res <- httr::GET(hb('/status/400')))
  expect_true(res$status_code == 400)
})

test_that("httr use_cassette works", {
  skip_if_not_installed("xml2")
  local_vcr_configure(dir = withr::local_tempdir())

  # recorded
  use_cassette("httr_test1", x <- httr::GET(hb("/404")))
  expect_s3_class(x, "response")
  expect_equal(x$status_code, 404)
  expect_equal(x$url, hb("/404"))
  expect_s3_class(x$request, "request")
  expect_equal(x$request$method, "GET")
  expect_equal(x$request$url, hb("/404"))
  expect_named(x$request$headers, c("Content-Type", "Accept"))
  expect_null(x$request$fields)
  expect_true(x$request$options$httpget)
  expect_s3_class(x$request$output, "write_function")

  # replayed
  use_cassette("httr_test1", x2 <- httr::GET(hb("/404")))
  expect_s3_class(x2$request, "request")
  expect_equal(x2$request$method, "GET")
  expect_equal(x2$request$url, hb("/404"))
  expect_named(x2$request$headers, "Accept")
  expect_null(x2$request$fields)
  expect_true(x2$request$options$httpget)
})

test_that("httr use_cassette works", {
  skip_if_not_installed("xml2")
  local_vcr_configure(dir = withr::local_tempdir())

  out <- use_cassette(
    "httr_test2",
    x <- httr::GET(hb("/404")),
    preserve_exact_body_bytes = TRUE
  )

  # cassette
  expect_s3_class(out, "Cassette")
  expect_match(out$file(), "httr_test2")

  # response
  expect_s3_class(x, "response")
  expect_equal(x$status_code, 404)
  expect_equal(x$url, hb("/404"))
})

test_that("httr w/ >1 request per cassette", {
  skip_if_not_installed("xml2")
  local_vcr_configure(dir = withr::local_tempdir())

  use_cassette("multiple_queries_httr_record_once", {
    x404 <- httr::GET(hb("/status/404"))
    x500 <- httr::GET(hb("/status/500"))
    x418 <- httr::GET(hb("/status/418"))

    expect_equal(httr::status_code(x404), 404)
    expect_equal(httr::status_code(x500), 500)
    expect_equal(httr::status_code(x418), 418)
  })

  # response
  expect_s3_class(x404, "response")
  expect_equal(x404$status_code, 404)
  expect_s3_class(x500, "response")
  expect_equal(x500$status_code, 500)
  expect_s3_class(x418, "response")
  expect_equal(x418$status_code, 418)

  # response body
  expect_match(vcr_last_request()$uri, "418")
  expect_match(vcr_last_response()$body$string, "teapot")
})

test_that("httr works with simple auth and hides auth details", {
  local_vcr_configure(dir = withr::local_tempdir())

  use_cassette(
    "httr_test_simple_auth",
    x <- httr::GET(hb("/basic-auth/foo/bar"), httr::authenticate("foo", "bar"))
  )
  # successful request
  expect_equal(x$status_code, 200)

  # no auth details in the cassette
  expect_false(has_name(vcr_last_request()$headers, "Authorization"))
})

test_that("string body works", {
  local_vcr_configure(dir = withr::local_tempdir(), match_requests_on = "body")

  body <- "thisisastring"

  # Check that we make the request correctly
  use_cassette("test", res1 <- httr::POST(hb_remote("/post"), body = body))
  content1 <- httr::content(res1, "parsed")
  expect_equal(content1$data, body)

  # Check that we can replay the request and get the same response
  use_cassette("test", res2 <- httr::POST(hb("/post"), body = body))
  content2 <- httr::content(res2, "parsed")
  expect_equal(content2, content1)
})

test_that("multipart body works", {
  local_vcr_configure(dir = withr::local_tempdir(), match_requests_on = "body")

  tempfile <- withr::local_tempfile(lines = "hello world")
  body <- list(x = "1", y = httr::upload_file(tempfile))

  # Check that we make the request correctly
  use_cassette("test", res1 <- httr::POST(hb("/post"), body = body))
  content1 <- httr::content(res1, "parsed")
  expect_equal(content1$form$x, "1")
  expect_equal(content1$files$y$filename, basename(tempfile))

  # Check that we can replay the request and get the same response
  use_cassette("test", res2 <- httr::POST(hb("/post"), body = body))
  content2 <- httr::content(res2, "parsed")
  expect_equal(content2, content1)
})

test_that("empty body works", {
  local_vcr_configure(dir = withr::local_tempdir(), match_requests_on = "body")

  body <- NULL

  # Check that we make the request correctly
  use_cassette("test", res1 <- httr::POST(hb("/post"), body = body))
  content1 <- httr::content(res1, "parsed")
  expect_length(content1$data, 0)
  expect_length(content1$files, 0)
  expect_length(content1$form, 0)

  # Check that we can replay the request and get the same response
  use_cassette("test", res2 <- httr::POST(hb("/post"), body = body))
  content2 <- httr::content(res2, "parsed")
  expect_equal(content2, content1)
})

test_that("JSON-encoded body", {
  local_vcr_configure(dir = withr::local_tempdir())

  ### matchers: method, uri, body
  # run it
  aa <- use_cassette(
    "testing2",
    res <- httr::POST(hb("/post"), body = list(foo = "bar"), encode = "json"),
    match_requests_on = c("method", "uri", "body")
  )
  # run it again
  bb <- use_cassette(
    "testing2",
    res <- httr::POST(hb("/post"), body = list(foo = "bar"), encode = "json"),
    match_requests_on = c("method", "uri", "body")
  )
  # the recorded_at time doesn't change
  # - that is, the request matched and the recorded response in aa
  # - was used
  expect_identical(recorded_at(aa), recorded_at(bb))
  expect_s3_class(aa, "Cassette")
  expect_type(aa$name, "character")
  expect_equal(aa$name, "testing2")
  expect_equal(aa$match_requests_on, c("method", "uri", "body"))

  # matching fails when the body changes
  expect_error(
    use_cassette(
      "testing2",
      res <- httr::POST(hb("/post"), body = list(foo = "baz"), encode = "json"),
      match_requests_on = "body"
    ),
    class = "vcr_unhandled"
  )

  # matching succeeds when the changed body is ignored
  cc <- use_cassette(
    "testing2",
    res <- httr::POST(hb("/post"), body = list(foo = "bar"), encode = "json"),
    match_requests_on = c("uri", "method")
  )
  expect_identical(recorded_at(aa), recorded_at(cc))
})


test_that("binary body uses bsae64 encoding", {
  local_vcr_configure(dir = withr::local_tempdir())
  path <- file.path(withr::local_tempdir(), "test.png")

  use_cassette(
    "test",
    httr::GET(hb("/image"), httr::add_headers("Accept" = "image/png"))
  )
  expect_named(vcr_last_response()$body, "raw_gzip")
})

test_that("can write files to disk", {
  dir <- withr::local_tempdir()
  local_vcr_configure(dir = dir)

  path <- file.path(withr::local_tempdir(), "image.png")
  download_image <- function() {
    httr::GET(
      hb("/image"),
      httr::add_headers("Accept" = "image/png"),
      httr::write_disk(path, TRUE)
    )
  }
  # First request uses httr path
  use_cassette("test", out <- download_image())
  expect_equal(normalizePath(out$content), normalizePath(path))

  # First seconds uses vcr path
  use_cassette("test", out2 <- download_image())
  expect_equal(
    out2$content,
    structure(file.path(dir, "test-files", "image.png"), class = "path")
  )

  # Content is the same
  expect_equal(httr::content(out, "raw"), httr::content(out2, "raw"))
})

test_that("match_requests_on - body", {
  local_vcr_configure(dir = withr::local_tempdir())

  ### matchers: method, uri, body
  # run it
  aa <- use_cassette(
    "testing2",
    res <- httr::POST(hb("/post"), body = list(foo = "bar")),
    match_requests_on = c("method", "uri", "body")
  )
  # run it again
  bb <- use_cassette(
    "testing2",
    res <- httr::POST(hb("/post"), body = list(foo = "bar")),
    match_requests_on = c("method", "uri", "body")
  )
  # the recorded_at time doesn't change
  # - that is, the request matched and the recorded response in aa
  # - was used
  expect_identical(recorded_at(aa), recorded_at(bb))
  expect_s3_class(aa, "Cassette")
  expect_type(aa$name, "character")
  expect_equal(aa$name, "testing2")
  expect_equal(aa$match_requests_on, c("method", "uri", "body"))

  ### matchers: method, body (uri ignored essentially)
  # run it
  aa <- use_cassette(
    "testing4",
    res <- httr::POST(
      hb("/post"),
      query = list(a = 5),
      body = list(foo = "bar")
    ),
    match_requests_on = c("method", "body")
  )
  # run it again
  bb <- use_cassette(
    "testing4",
    res <- httr::POST(
      hb("/post"),
      query = list(b = 2),
      body = list(foo = "bar")
    ),
    match_requests_on = c("method", "body")
  )
  # the recorded_at time doesn't change
  # - that is, the request matched and the recorded response in aa
  # - was used
  expect_identical(recorded_at(aa), recorded_at(bb))
  expect_s3_class(aa, "Cassette")
  expect_type(aa$name, "character")
  expect_equal(aa$name, "testing4")
  expect_equal(aa$match_requests_on, c("method", "body"))

  ### matchers: body only
  # run it
  aa <- use_cassette(
    "testing5",
    res <- httr::POST(hb("/post"), body = list(foo = "bar")),
    match_requests_on = "body"
  )
  # run it again, method and uri changed
  bb <- use_cassette(
    "testing5",
    res <- httr::PUT(hb("/put"), body = list(foo = "bar")),
    match_requests_on = "body"
  )
  # run it again, method and uri changed again
  cc <- use_cassette(
    "testing5",
    res <- httr::PATCH(hb("/patch"), body = list(foo = "bar")),
    match_requests_on = "body"
  )
  # the recorded_at time doesn't change
  # - that is, the request matched and the recorded response in aa
  # - was used
  expect_identical(recorded_at(aa), recorded_at(bb))
  expect_identical(recorded_at(bb), recorded_at(cc))
  expect_s3_class(aa, "Cassette")
  expect_type(aa$name, "character")
  expect_equal(aa$name, "testing5")
  expect_equal(aa$match_requests_on, "body")
  expect_equal(bb$match_requests_on, "body")

  ### matchers: host and path only (notice how HTTP method and query are ignored)
  # run it
  aa <- use_cassette(
    "testing_httr_host_path",
    res <- httr::GET("https://ropensci.org/about", query = list(b = 99999)),
    match_requests_on = c("host", "path")
  )
  # run it again
  bb <- use_cassette(
    "testing_httr_host_path",
    res2 <- httr::POST("https://ropensci.org/about", query = list(a = 5)),
    match_requests_on = c("host", "path")
  )
  # the recorded_at time doesn't change
  # - that is, the request matched and the recorded response in aa
  # - was used
  expect_identical(recorded_at(aa), recorded_at(bb))
  expect_s3_class(aa, "Cassette")
  expect_type(aa$name, "character")
  expect_equal(aa$name, "testing_httr_host_path")
  expect_equal(aa$match_requests_on, c("host", "path"))
})

Try the vcr package in your browser

Any scripts or data that you put into this service are public.

vcr documentation built on Aug. 8, 2025, 6:45 p.m.