Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: How to mock server response from an URL? #101

Open
KajeArch opened this issue Aug 3, 2022 · 2 comments
Open

Question: How to mock server response from an URL? #101

KajeArch opened this issue Aug 3, 2022 · 2 comments

Comments

@KajeArch
Copy link

KajeArch commented Aug 3, 2022

I don't know if this belongs here, but I need a bit of an advice and I'm having quite a hard time figuring this out as JS seems a bit painful to me. Say, we send a typical GET request to an URL, like https://www.example.com/ with some string (doesn't matter what it is) and we receive the respond from the real server: "example string". How could I use mockttp to now "catch" this certain HTTP response and, say, mock a server response that replies with a different string, like "oh that's my own!" ?

@hanvyj
Copy link
Contributor

hanvyj commented Aug 3, 2022

What we do is have a configuration field serverUrl; say. In production the configuration is set to serverUrl = https://www.example.com;, however, in testing you set this to serverUrl = http://localhost:3000;.

Before your test runs you can set up mockttp to respond with "oh that's my own!" like in the examples:

const superagent = require("superagent");
const mockServer = require("mockttp").getLocal();
const config = require("./config");

// Set the test config in some way 
config.serverUrl = "http://localhost:3000";

describe("Mockttp", () => {
    // Start your mock server
    beforeEach(() => mockServer.start(3000));
    afterEach(() => mockServer.stop());

    it("lets you mock requests, and assert on the results", async () => {
        // Mock your endpoints
        await mockServer.forGet("/").thenReply(200, "oh that's my own!");

        // Make a request
        const response = myTestFunctionThatCallsGet();

        // Assert on the results
        expect(response.text).to.equal("oh that's my own!");
    });
});

Mockttp doesn't "intercept" anything, it spins up a fake/mock server on your local machine that you can describe responses for, then call as if it was a real server. You point your code at the "mock" local server when running a test.

@pimterry
Copy link
Member

pimterry commented Aug 4, 2022

Mockttp doesn't "intercept" anything, it spins up a fake/mock server on your local machine that you can describe responses for, then call as if it was a real server.

@hanvyj your code does that, yes, and that's one solution, but it is also possible to use Mockttp to intercept traffic. In addition to acting as an HTTP server, it can act as an HTTP proxy.

To do so, you need to start Mockttp, configure the target client to use it as a proxy server (and to trust its certificate, if you're using HTTPS). Then you can provide a fake response for any URL.

Here's a full example, setting a proxy with superagent:

const { expect } = require('chai');

const superagent = require("superagent");
require("superagent-proxy")(superagent);

const mockServer = require("mockttp").getLocal();

describe("Mockttp", () => {
    // Start your mock server
    beforeEach(() => mockServer.start(3000));
    afterEach(() => mockServer.stop());

    it("lets you mock requests, and assert on the results", async () => {
        // Match requests to a certain URL, and define a fake response:
        await mockServer.forGet("example.com").thenReply(200, "oh that's my own!");

        const response = await superagent.get("http://example.com") // Make a request to any URL
            .proxy(mockServer.url); // Using Mockttp as a proxy

        // Assert on the results
        expect(response.text).to.equal("oh that's my own!");
    });
});

In this example, we're mocking the response completely, so the request appears to go to example.com, but never actually leaves your machine.

If you want to do exactly what you described @KajeArch, to send a real request and then 'use mockttp to now "catch" this certain HTTP response and, say, mock a server response' then you can proxy the requests to the real server and update the response after it's returned instead, by changing the mockServer.forGet(...) rule defined above to this:

mockServer.forGet("example.com").thenPassThrough({
    beforeResponse: (res) => {
        // This will run after every response from example.com. You can read the
        // real response from 'res', and then return an object that will override
        // parts of it. Such as:
        return {
            status: 200,
            body: "oh that's my own!"
        };
    }
});

Does that make sense? All these approaches (creating a mock server, or proxying & mocking URLs directly, or proxying traffic & modifying the result) are equally correct & supported, it just depends on your use case. If you are particularly interested in proxying traffic, you might find this guide useful: https://httptoolkit.tech/blog/javascript-mitm-proxy-mockttp/.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants