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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: How to mock api calls in parallel in tests? #109

Open
samatar26 opened this issue Nov 9, 2022 · 3 comments
Open

Question: How to mock api calls in parallel in tests? #109

samatar26 opened this issue Nov 9, 2022 · 3 comments

Comments

@samatar26
Copy link

Hellooooo 馃憢馃従

I'm really liking the library so far, really amazing work!! 馃挴

I've been using it combination with Playwright and Next.js and seem to be stumped by mocking server side requests in parallel as the tests will be running in parallel. The api url I want to mock is http://localhost:3005/api and I think this would mean I would need to start a mockServer on port 3005 blocking me from running the tests in parallel.

I could change the api url, but not entirely sure to what (I think to a non-localhost one? but struggled to intercept the request) and was wondering if you had any ideas/suggestions to enable multiple mockServers or maybe even 1 mockServer but it somehow magically knowing where the request came from and replying with the correct body/mock specified in the test?

Thank you so much for looking into this, really appreciate it!!

@pimterry
Copy link
Member

Hi @samatar26! 馃憢

I'm afraid there's no easy single answer, but there's a lot of options. In practice, if you want mocks for independent tests, the best way is definitely to run a separate Mockttp instance for each test.

That means either:

  • Using a different API URL for each parallel test, or
  • Using any API URL, but with separate proxy port for each parallel test runner (which effectively means running a separate browser config) so each one uses a different Mockttp instance as the proxy, and then the traffic to any API URL (or elsewhere) can be captured.

Depends on your setup, but particularly how easy it is for you to inject API config into the code your testing. If you can easily pass that, then the first option will be easy and that's the best approach. If not, you'll need to find a way to set different browser config to make that work.

For actual proxying, with Chrome, you just need to set the --proxy-server=localhost:$PORT with your Mockttp server's port, and then you can mock any URL like mockServer.forGet('http://example.com/api').thenReply(404).

If you're intercepting HTTPS too, you'll also need to set --ignore-certificate-errors-spki-list=$CERT_FINGERPRINT with the fingerprint of your cert. Mockttp exports a generateSPKIFingerprint(certPEMString) method to calculate this for you.

There's an intro to proxying traffic with Mockttp more generally (not for testing specifically) over here: https://httptoolkit.com/blog/javascript-mitm-proxy-mockttp/

Does that make sense? There's no clear answer but Mockttp provides a few different ways you can do this depending on exactly how your setup works.

@samatar26
Copy link
Author

Thanks for responding @pimterry, much appreciated! I don't think the solutions you've provided will work for me, but it could also be that I'm just not fully getting it sorry. I think I should describe my setup in a little bit more detail to see if it still makes sense for you:

  • I have one instance of a Next.js app running, so 1 server + frontend
  • I'm running tests using Playwright, here is an example of what a test may look like:
    test('I can login', async ({ loginPage }) => {
      await loginPage.goto();
      await loginPage.fillEmail('myemail@test.com');
      ....
    });

The test will open a browser, navigate to the login page, say localhost:8000/login and the browser will first hit the Next.js server. And this Next.js server can also potentially make a network request. Intercepting network requests from the browser is no problem as the test framework provides some helpful methods to mock the requests. The real fun starts with intercepting a request coming from the app's server.

What I've done so far is start a mockttp server and run it on the same port as the Next.js API_URL, let's say localhost:8888. This works fine and allows me to mock the Next.js server side requests, but only when I run the tests in sequence.

In order to run the tests in parallel, I think I need to run several mockttp instances (1 for each test?) and allow mockttp to choose a port at random and am struggling to think of a way to make this work. Let me know if I'm making any sense at all 馃槢 and thanks again for helping/looking into this!

@pimterry
Copy link
Member

I think I need to run several mockttp instances (1 for each test?) and allow mockttp to choose a port at random and am struggling to think of a way to make this work

Yes, exactly that - you'll need to create a separate Mockttp instance for each test, start it, and then pass the port that instance starts on to your server somehow.

Unfortunately, given this constraint:

I have one instance of a Next.js app running, so 1 server + frontend

I think you're stuck. If you have one instance of the app running with parallel tests, all requests are all going to end up doing the same thing.

Without a mechanism to tell from a server-side request which test it's related to, you're not going to be able to handle the requests independently for each test.

If you want parallel testing in this setup with different Mockttp configuration for each test, you need to either:

  • Run a separate app instance for each parallel testing thread
  • Or pass through some data from the test that you can match in Mockttp (e.g. use a test-id user-agent header, which the server receives and passes on in its requests somehow, and which you can then match in 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

2 participants