1

I'm very new to Node.js, so I might just not be getting it, but after searching quite a bit, and trying a few different solutions, I am still not able to find a decent way to mock API responses using Node for acceptance testing.

I've got a javascript app (written in elm actually) that interacts with an API (pretty common, I imagine), and I want to write some acceptance tests... so I setup WebdriverIO with selenium and mocha, write some tests, and of course now I need to mock some API responses so that I can setup some theoretical scenarios to test under.

mock-api-server: Looked pretty nice, but there's no way to adjust the headers getting sent back from the server!

mock-http-server: Also looked pretty nice, lets me adjust headers, but there's no way to reset the mock responses without shutting down the whole server... !? And that has issues because the server won't shut down while the browser window is still open, so that means I have to close and relauch the browser just to clear the mocks!

json-server: Simple and decent way to mock some responses, but it relies entirely on files on disk for the responses. I want something I can configure from within a test run without reading and writing files to disk.

Am I missing something? Is this not how people do acceptance testing in the Node universe? Does everyone just use a fixed set of mock data for their entire test suite? That just sounds insane to me... Particularly since it seems like it wouldn't be that hard to write a good one based on express server that has all the necessary features... does it exist?

Necessary Features:

  1. Server can be configured and launched from javascript
  2. Responses(including headers) can be configured on the fly
  3. Responses can also be reset easily on the fly, without shutting down the server.
mltsy
  • 6,598
  • 3
  • 38
  • 51
  • Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are ***off-topic for Stack Overflow*** as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it. – jfriend00 Mar 03 '17 at 01:24
  • 1
    People don't usually mock at the http level because that would slow down unit tests (mocking are mostly for unit tests, acceptance tests in my experience don't mock, they simulate) – slebetman Mar 03 '17 at 03:43
  • @jfriend00 - sorry, I will change the title of the question to be a little bit more to the point. Unfortunately, I'm in new territory, so I don't know quite how to ask the right questions yet! But I got the answer I was after (from both slebetman and rsp) – mltsy Mar 03 '17 at 16:56
  • You may want to familiarize yourself with [What topics can I ask about here](http://stackoverflow.com/help/on-topic) from the Help Center. Stackoverflow remains a high quality resource because the community is fairly strict about making sure that posts are on topic. – jfriend00 Mar 03 '17 at 17:02
  • Hmm... I feel like this generally covers "software tools commonly used by programmers" and is "a practical, answerable problem that is unique to software development"... I know some ask unanswerable questions like "What's the best editor?", but my intention here was qualitatively different. I really just wanted to understand what I was missing that such a library, which seemed to me to be integral to functional testing, didn't exist, to aid my understanding of how client-side apps are generally tested. I will try to word similar questions more appropriately in the future :) – mltsy Mar 03 '17 at 17:12
  • To follow-up, I ended up using the `fakeServer` feature of [Sinon.js](http://sinonjs.org), which, while it is not a fully functional HTTP server, does work for my situation, where my app is running in a browser, because Sinon mocks the browser's xmlHttpRequest functionality. It was a bit of a trick to expose the mocking functionality to my test suite which is external to the browser (through selenium's execute function, via WebdriverIO), but it works very well, and is quite maintainable now. – mltsy May 17 '17 at 16:51

3 Answers3

2

I hit this problem too, so I built one: https://github.com/pimterry/mockttp

In terms of the things you're looking for, Mockttp:

  • Lets you start & reconfigure the server dynamically from JS during the test run, with no static files.
  • Lets you adjust headers
  • Lets you reset running servers (though I'd recommend shutting down & restarting anyway - with Mockttp that takes milliseconds, is clear & easily automatable, and gives you some nice guarantees)

On top of that, it:

  • Is configurable from both Node & browsers with identical code, so you can test universally
  • Can handle running tests in parallel for quicker testing
  • Can fake HTTPS servers, self-signing certificates automatically
  • Can mock as an intercepting proxy
  • Has a bunch of nice debugging support for when things go wrong (e.g. unmatched requests come back with a readable explanation of the current configuration, and example code that would make the request succeed)

Just to quickly comment on the other posts suggesting testing in-process: I really wouldn't. Partly because a whole bunch of limitations (you're tied to a specific environment, potentially even specific node version, you have to mock for the whole process, so no parallel tests, and you can't mock subprocesses), but mainly because it's not truly representative. For a very very small speed cost, you can test with real HTTP, and know that your requests & responses will definitely work in reality too.

Tim Perry
  • 11,766
  • 1
  • 57
  • 85
  • 1
    Wow! Awesome work :D I'm on a new project now, but this looks like it would have been perfect! – mltsy Feb 21 '18 at 04:29
1

Is this not how people do acceptance testing in the Node universe? Does everyone just use a fixed set of mock data for their entire test suite?

No. You don't have to make actual HTTP requests to test your apps.

All good test frameworks lets you fake HTTP by running the routes and handlers without making network requests. Also you can mock the functions that are making the actual HTTP requests to external APIs, which should be abstracted away in the first place, so no actual HTTP requests need to take place here as well.

And if that's not enough you can always write a trivially simple server using Express, Hapi, Restify, Loopback or some other frameworks, or plain http, or even net module (depending on how much control do you need - for example you should always test invalid responses that don't use HTTP protocol correctly, or broken connections, incomplete connections, slow connections etc. and for that you may need to use lower lever APIs in Node) to provide the mock data yourself.

By the way, you also always need to test responses with invalid JSON because people often wrongly assume that the JSON they get is always valid which it is not. See this answer to see why it is particularly important:

Particularly since it seems like it wouldn't be that hard to write a good one based on express server that has all the necessary features... does it exist?

Not everything that "wouldn't be that hard to write" necessarily has to exist. You may need to write it. Hey, you even have a road map ready:

Necessary Features:

  1. Server can be configured and launched from javascript
  2. Responses(including headers) can be configured on the fly
  3. Responses can also be reset easily on the fly, without shutting down the server.

Now all you need is choose a name, create a repo on GitHub, create a project on npm and start coding.

You now, even "it wouldn't be that hard to write" it doesn't mean that it will write itself. Welcome to the open source world where instead of complaining that something doesn't exist people just write it.

Community
  • 1
  • 1
rsp
  • 107,747
  • 29
  • 201
  • 177
  • Oh, I wasn't "complaining that something doesn't exist." I was just in disbelief that it doesn't exist, and was legitimately asking if it did, or what I was missing if it didn't. I'm happy to write something, but it's a waste of effort if I'm just missing the point because I'm new to the landscape, which seems to be the case here :) What I was overlooking was that everybody in the regular JS world (and every other language really) mocks the HTTP connection rather than mocking a server. I am having a hard time doing that, because my project is written in ELM. So that explains it! :) – mltsy Mar 03 '17 at 16:50
  • I'll give you the answer since your first sentence and following paragraph really addressed my question - even if the rest of it felt a little patronizing ;) Thanks for the quick explanation! – mltsy Mar 03 '17 at 17:02
0

You could try nock. https://github.com/node-nock

It supports all of your feature requests.

bigkahunaburger
  • 426
  • 5
  • 10
  • Ah! Thanks for the recommendation! It may indeed meet all of the feature expectations I outlined, but unfortunately I was looking for something that acts as an actual server, because my app is not a Node app. It's an Elm app that happens to be compiled and run with Node (webpack). So I was looking for a fully functional mock server (like the ones referenced) that would be convenient to setup and run within my Node test environment (but which is testing a non-Node app). – mltsy May 17 '17 at 16:47
  • @mltsy maybe some server around node-nock exposing nock API would do the trick ? – sylvain Dec 04 '17 at 11:05