Webmockr
Stub and set expectations on HTTP requests
Install / Use
/learn @ropensci/WebmockrREADME
webmockr
<!-- NOTE: run `make readme` to generate the README.md -->R library for stubbing and setting expectations on HTTP requests.
Port of the Ruby gem webmock
<details> <summary><strong>How it works in detail</strong></summary> <p> <p>The very very short version is: <code>webmockr</code> helps you stub HTTP requests so you don’t have to repeat yourself.</p> <p><strong>More details</strong></p> <p>You tell <code>webmockr</code> what HTTP request you want to match against and if it sees a request matching your criteria it doesn’t actually do the HTTP request. Instead, it gives back the same object you would have gotten back with a real request, but only with the bits it knows about. For example, we can’t give back the actual data you’d get from a real HTTP request as the request wasn’t performed.</p> <p>In addition, if you set an expectation of what <code>webmockr</code> should return, we return that. For example, if you expect a request to return a 418 error (I’m a Teapot), then that’s what you’ll get.</p> <p><strong>What you can match against</strong></p> <ul> <li>HTTP method (required)</li> </ul> <p>Plus any single or combination of the following:</p> <ul> <li>URI <ul> <li>Right now, we can match directly against URI’s, and with regex URI patterns. Eventually, we will support RFC 6570 URI templates.</li> <li>We normalize URI paths so that URL encoded things match URL un-encoded things (e.g. <code>hello world</code> to <code>hello%20world</code>)</li> </ul></li> <li>Query parameters <ul> <li>We normalize query parameter values so that URL encoded things match URL un-encoded things (e.g. <code>message = hello world</code> to <code>message = hello%20world</code>)</li> </ul></li> <li>Request headers <ul> <li>We normalize headers and treat all forms of same headers as equal. For example, the following two sets of headers are equal: <ul> <li><code>list(H1 = "value1", content_length = 123, X_CuStOm_hEAder = "foo")</code></li> <li><code>list(h1 = "value1", "Content-Length" = 123, "x-cuSTOM-HeAder" = "foo")</code></li> </ul></li> </ul></li> <li>Request body</li> </ul> <p><strong>Real HTTP requests</strong></p> <p>There’s a few scenarios to think about when using <code>webmockr</code>:</p> <p>After doing</p> <pre class="r"><code>library(webmockr)</code></pre> <p><code>webmockr</code> is loaded but not turned on. At this point <code>webmockr</code> doesn’t change anythning.</p> <p>Once you turn on <code>webmockr</code> like</p> <pre class="r"><code>webmockr::enable()</code></pre> <p><code>webmockr</code> will now by default not allow real HTTP requests from the http libraries that adapters are loaded for (right now only <code>crul</code>).</p> <p>You can optionally allow real requests via <code>webmockr_allow_net_connect()</code>, and disallow real requests via <code>webmockr_disable_net_connect()</code>. You can check whether you are allowing real requests with <code>webmockr_net_connect_allowed()</code>.</p> <p>Certain kinds of real HTTP requests allowed: We don’t suppoprt this yet, but you can allow localhost HTTP requests with the <code>allow_localhost</code> parameter in the <code>webmockr_configure()</code> function.</p> <p><strong>Storing actual HTTP responses</strong></p> <p><code>webmockr</code> doesn’t do that. Check out <a href="https://github.com/ropensci/vcr">vcr</a></p> </p></details>Features
- Stubbing HTTP requests at low http client lib level
- Setting and verifying expectations on HTTP requests
- Matching requests based on method, URI, headers and body
- Can be used for testing or outside of a testing context
- Supports async http request mocking with
crulonly
Supported HTTP libraries
Install
from cran
install.packages("webmockr")
Dev version
# install.packages("pak")
pak::pak("ropensci/webmockr")
library(webmockr)
Enable webmockr
webmockr::enable()
#> CrulAdapter enabled!
#> HttrAdapter enabled!
#> Httr2Adapter enabled!
Inside a test framework
library(crul)
library(testthat)
# make a stub
stub_request("get", "https://httpbin.org/get") %>%
to_return(body = "success!", status = 200)
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query:
#> body:
#> request_headers:
#> auth:
#> to_return:
#> - status: 200
#> body: success!
#> response_headers:
#> should_timeout: FALSE
#> should_raise: FALSE
# check that it's in the stub registry
stub_registry()
#> <webmockr stub registry>
#> Registered Stubs
#> GET: https://httpbin.org/get | to_return: with body "success!" with status 200
# make the request
z <- crul::HttpClient$new(url = "https://httpbin.org")$get("get")
# run tests (nothing returned means it passed)
expect_is(z, "HttpResponse")
expect_equal(z$status_code, 200)
expect_equal(z$parse("UTF-8"), "success!")
Outside a test framework
library(crul)
Stubbed request based on uri only and with the default response
stub_request("get", "https://httpbin.org/get")
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query:
#> body:
#> request_headers:
#> auth:
#> to_return:
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get')
#> <crul response>
#> url: https://httpbin.org/get
#> request_headers:
#> User-Agent: libcurl/8.14.1 r-curl/6.4.0 crul/1.5.1.95
#> Accept-Encoding: gzip, deflate
#> Accept: application/json, text/xml, application/xml, */*
#> response_headers:
#> status: 200
set return objects
stub_request("get", "https://httpbin.org/get") %>%
wi_th(
query = list(hello = "world")
) %>%
to_return(status = 418)
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query: hello=world
#> body:
#> request_headers:
#> auth:
#> to_return:
#> - status: 418
#> body:
#> response_headers:
#> should_timeout: FALSE
#> should_raise: FALSE
x$get('get', query = list(hello = "world"))
#> <crul response>
#> url: https://httpbin.org/get
#> request_headers:
#> User-Agent: libcurl/8.14.1 r-curl/6.4.0 crul/1.5.1.95
#> Accept-Encoding: gzip, deflate
#> Accept: application/json, text/xml, application/xml, */*
#> response_headers:
#> status: 418
Stubbing requests based on method, uri and query params
stub_request("get", "https://httpbin.org/get") %>%
wi_th(
query = list(hello = "world"),
headers = list(
'User-Agent' = 'libcurl/7.51.0 r-curl/2.6 crul/0.3.6',
'Accept-Encoding' = "gzip, deflate"
)
)
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query: hello=world
#> body:
#> request_headers: User-Agent=libcurl/7.51.0 r-cur..., Accept-Encoding=gzip, deflate
#> auth:
#> to_return:
stub_registry()
#> <webmockr stub registry>
#> Registered Stubs
#> GET: https://httpbin.org/get
#> GET: https://httpbin.org/get with query params hello=world | to_return: with status 418
#> GET: https://httpbin.org/get with query params hello=world with headers {"User-Agent":"libcurl/7.51.0 r-curl/2.6 crul/0.3.6","Accept-Encoding":"gzip, deflate"}
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get', query = list(hello = "world"))
#> <crul response>
#> url: https://httpbin.org/get
#> request_headers:
#> User-Agent: libcurl/8.14.1 r-curl/6.4.0 crul/1.5.1.95
#> Accept-Encoding: gzip, deflate
#> Accept: application/json, text/xml, application/xml, */*
#> response_headers:
#> status: 418
Stubbing requests and set expectation of a timeout
stub_request("post", "https://httpbin.org/post") %>% to_timeout()
#> <webmockr stub>
#> method: post
#> uri: https://httpbin.org/post
#> with:
#> query:
#> body:
#> request_headers:
#> auth:
#> to_return:
#> - status:
#> body:
#> response_headers:
#> should_timeout: TRUE
#> should_raise: FALSE
x <- HttpClient$new(url = "https://httpbin.org")
x$post('post')
#> Error: Request Timeout (HTTP 408).
#> - The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.
Stubbing requests and set HTTP error expectation
library(fauxpas)
stub_request("get", "https://httpbin.org/get?a=b") %>% to_raise(HTTPBadRequest)
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get?a=b
#> with:
#> query:
#> body:
#> request_headers:
#> auth:
#> to_return:
#> - status:
#> body:
#> response_headers:
#> should_timeout: FALSE
#> should_raise: HTTPBadRequest
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get', query = list(a = "b"))
#> Error: Bad Request
Related Skills
gh-issues
335.9kFetch GitHub issues, spawn sub-agents to implement fixes and open PRs, then monitor and address PR review comments. Usage: /gh-issues [owner/repo] [--label bug] [--limit 5] [--milestone v1.0] [--assignee @me] [--fork user/repo] [--watch] [--interval 5] [--reviews-only] [--cron] [--dry-run] [--model glm-5] [--notify-channel -1002381931352]
node-connect
335.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
82.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Writing Hookify Rules
82.7kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
