diff --git a/NEWS.md b/NEWS.md index ae13e03..afa3de7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # httptest2 1.1.0.9000 +* `build_mock_url()` now works with multipart body request containing character strings or raw data (#40, @jmaspons) + # httptest2 1.1.0 * `request` is now removed when saving `httr2_response` objects. In earlier versions of `httr2`, requests were not included in responses, but in httr2 1.0.0, [they were added](https://github.com/r-lib/httr2/pull/359) in order to improve error messages. *If you recorded any responses with httr2 >= 1.0 and httptest2 prior to this version, you may have leaked auth secrets: this would happen if your requests included auth information (as in an `Authentication` header), and the response was saved in a .R file, not simplified to .json or other response-body-only formats. Please inspect your recorded responses and invalidate any tokens that were exposed.* @@ -38,4 +40,4 @@ Changes to function signatures: * The `path` argument to `capture_requests()` and `start_capturing()` has been removed; instead set the mock path explicitly with `.mockPaths()` or use `with_mock_dir()`. * Internal function `save_response()` requires a `file` path argument because `httr2_response` objects do not contain their `request`, which is needed to construct the mock file path -* Internal function `build_mock_url()` no longer accepts a string URL as an input; it only accepts `request` objects \ No newline at end of file +* Internal function `build_mock_url()` no longer accepts a string URL as an input; it only accepts `request` objects diff --git a/R/build-mock-url.R b/R/build-mock-url.R index 74bd752..9c9315f 100644 --- a/R/build-mock-url.R +++ b/R/build-mock-url.R @@ -79,9 +79,11 @@ get_string_request_body <- function(req) { if (inherits(x, "form_file")) { # hash the file contents paste("File:", digest(x$path, serialize = FALSE, file = TRUE)) - } else { - # assume form_data + } else if (inherits(x, "form_data")) { rawToChar(x$value) + } else { + # assume character string or raw + x } }) b <- paste(c( diff --git a/tests/testthat/test-capture-requests.R b/tests/testthat/test-capture-requests.R index 94a38dd..2e1a6f9 100644 --- a/tests/testthat/test-capture-requests.R +++ b/tests/testthat/test-capture-requests.R @@ -1,6 +1,8 @@ d <- tempfile() dl_file <- tempfile() webp_file <- tempfile() +file_path <- tempfile() +cat(letters[1:6], file = file_path) # The webfake URL will be something like 127.0.0.1:port, and port may vary # so the mock paths will be different every time it runs @@ -31,6 +33,15 @@ test_that("We can record a series of requests (a few ways)", { req_perform(path = webp_file) r8 <<- request(httpbin$url("/status/202")) %>% req_perform() r9 <<- request(httpbin$url("/status/200")) %>% req_perform() + r10 <<- request(httpbin$url("/post")) %>% + req_body_multipart( + file = curl::form_file(file_path), + string = "some text", + form_data = curl::form_data("form data"), + raw_data = charToRaw("raw data") + ) %>% + req_method("POST") %>% + req_perform() stop_capturing() }) @@ -41,6 +52,7 @@ test_that("We can record a series of requests (a few ways)", { "httpbin.org/get.json", "httpbin.org/image/webp.R", # Not a simplifiable format, so .R "httpbin.org/image/webp.R-FILE", # The `write_disk` location + "httpbin.org/post-48db67-POST.json", "httpbin.org/put-PUT.json", # Not a GET, but returns 200 "httpbin.org/response-headers-ac4928.json", "httpbin.org/status/200.txt", # empty 200 response "text/plain", so .txt @@ -94,6 +106,15 @@ test_that("We can then load the mocks it stores", { req_perform(path = mock_webp_file) m8 <- request(httpbin$url("/status/202")) %>% req_perform() m9 <- request(httpbin$url("/status/200")) %>% req_perform() + m10 <- request(httpbin$url("/post")) %>% + req_body_multipart( + file = curl::form_file(file_path), + string = "some text", + form_data = curl::form_data("form data"), + raw_data = charToRaw("raw data") + ) %>% + req_method("POST") %>% + req_perform() }) }) expect_identical(resp_body_json(m1), resp_body_json(r1)) @@ -114,6 +135,7 @@ test_that("We can then load the mocks it stores", { expect_equal(resp_status(m9), 200) expect_equal(resp_content_type(m9), "text/plain") expect_false(resp_has_body(m9)) + expect_identical(resp_body_json(m10), resp_body_json(r10)) }) test_that("write_disk mocks can be reloaded even if the mock directory moves", { diff --git a/tests/testthat/test-mock-api.R b/tests/testthat/test-mock-api.R index beea45c..4a10434 100644 --- a/tests/testthat/test-mock-api.R +++ b/tests/testthat/test-mock-api.R @@ -175,13 +175,17 @@ with_mock_api({ r %>% req_body_multipart( a = curl::form_file(file_to_upload), - b = curl::form_data("strings") + b = curl::form_data("strings"), + c = "some text", + d = charToRaw("raw data") ) %>% req_perform(), "http://httpbin.not/post", "Multipart form: a = File: ae2b1fca515949e5d54fb22b8ed95575 - b = strings" + b = strings + c = some text + d = as.raw(c(0x72, 0x61, 0x77, 0x20, 0x64, 0x61, 0x74, 0x61))" ) })