4 releases

0.2.0 Nov 4, 2021
0.1.2 Jul 20, 2021
0.1.1 Jul 14, 2021
0.1.0 May 31, 2021

#374 in HTTP client

Download history 5/week @ 2024-03-12 1/week @ 2024-03-26 12/week @ 2024-04-02 1/week @ 2024-04-23 1/week @ 2024-05-28 1/week @ 2024-06-04 114/week @ 2024-06-11

115 downloads per month
Used in 2 crates

MPL-2.0 license

28KB
404 lines

Surf-vcr - Record and Replay HTTP sessions

Surf-vcr is a testing middleware for the Surf HTTP client library. Surf-vcr records your client's HTTP sessions with a server to later mock the server's HTTP responses, providing deterministic testing of your clients.

The high-level design is based on VCR for Ruby.

Source code is available on SourceHut and Github. Patches may be sent via either service, but the CI is running on SourceHut.

Table of Contents

Introduction

Surf-vcr records HTTP sessions to a YAML file so you can review and modify (or even create) the requests and responses manually. You can then inject the pre-recorded responses into your client sessions.

Install

You'll typically be using surf-vcr as a development dependency, so add it as such via Cargo:

cargo add -D surf-vcr

Or add it to your Cargo.toml file manually:

[dev-dependencies]
surf-vcr = "0.2.0"

Record

Either in your application or the relevant test, register the middleware with your application in Record mode. You will connect to a functioning server and record all requests and responses to a file. You can safely replay and record multiple HTTP sessions (tests) with the same file concurrently.

Surf-vcr must be registered after any other middleware that modifies the Request or Response; otherwise it will not see their modifications and cannot record them.

I have found it useful to use a function in my application to create the Surf client with my middleware, then call that function in my tests as well so I know my test client and application client are identical:

fn create_surf_client() -> surf::Client {
    let session = MySessionMiddleware::new();

    surf::Client::new()
        .with(session)
}

#[cfg(test)]
mod tests {
    use super::*;
    use async_std::task;
    use surf_vcr::{VcrError, VcrMiddleware, VcrMode};

    async fn create_test_client(mode: VcrMode, cassette: &'static str)
    -> std::result::Result<surf::Client, VcrError>
    {
        let client = create_surf_client()
            .with(VcrMiddleware::new(mode, cassette).await?);

        Ok(client)
    }

    #[async_std::test]
    async fn test_example_request() {
        let client = create_test_client(
            mode::VcrMode::Record,
            "sessions/my-session.yml"
        ).await.unwrap();

        let req = surf::get("https://www.example.com")
            .insert_header("X-my-header", "stuff");

        let mut res = client.send(req).await.unwrap();
        assert_eq!(res.status(), surf::StatusCode::Ok);

        let content = res.body_string().await.unwrap();
        assert!(content.contains("illustrative examples"));
    }
}

Take a look at the docs or the simple example for more.

Playback

To mock the server's responses simply change VcrMode::Record to VcrMode::Replay and re-run your tests. Surf-vcr will look up each request made, intercept it, and return the saved response.

Modify Recorded Content

You can modify data before writing to your cassette files. This is useful while working with sensitive or dynamic data.

VcrMiddleware::new(VcrMode::Record, path).await?
    .with_modify_request(|req| {
        req.headers
            .entry("session-key".into())
            .and_modify(|val| *val = vec!["...(erased)...".into()]);
    })
    .with_modify_response(|res| {
        res.headers
            .entry("Set-Cookie".into())
            .and_modify(|val| *val = vec!["...(erased)...".into()]);
    });

License

All source code is licensed under the terms of the MPL 2.0 license.

Contributing

Patches and pull requests are welcome. For major features or breaking changes, please open a ticket or start a discussion first so we can discuss what you would like to do.

Dependencies

~8–21MB
~327K SLoC