1# FakeRegistry 2 3This is a replacement for npm-registry-mock in times where its fixtures are 4not used. (Adding support for its standard fixtures is TODO, but should be 5straightforward—tacks-ify them and call `mr.mock…` 6 7# Usage 8 9The intent is for this to be a drop in replacement for npm-registry-mock 10(and by extension hock). New scripts will be better served using its native 11interface, however. 12 13# Main Interface 14 15## Logging 16 17All requests the mock registry receives are logged at the `http` level. You can 18see these by running your tests with: 19 20``` 21npm --loglevel=http run tap test/tap/name-of-test.js 22``` 23 24Or directly with: 25 26``` 27npm_config_loglevel=http node test/tap/name-of-test.js 28``` 29 30## Construction 31 32Ordinarily there's no reason to construct more than one FakeRegistyr object 33at a time, as it can be entirely reset between tests, so best practice 34would be to use its singleton. 35 36``` 37const common = require('../common-tap.js') 38const mr = common.fakeRegistry 39``` 40 41If you have need of multiple registries at the same time, you can construct 42them by hand: 43 44``` 45const common = require('../common-tap.js') 46const FakeRegistry = common.fakeRegistry.FakeRegistry 47const mr = new FakeRegistry(opts) 48``` 49 50## new FakeRegistry(opts) 51 52Valid options are: 53 54* `opts.port` is the first port to try when looking for an available port. If it 55 is unavialable it will be incremented until one available is found. 56 57 The default value of `port` is taken from `common.npm`. 58 59* `opts.keepNodeAlive` will instruct FakeRegistry to not unref the 60 underlying server. 61 62## mr.reset() → this 63 64Reset all mocks to their default values. Further requests 65 66## mr.listen() → Promise(mr) 67 68Start listening for connections. The promise resolves when the server is 69online and ready to accept connections. 70 71`mr.port` and `mr.registry` contain the port that was actually selected. 72 73To ease compatibility, `common` will also have its `port` and `registry` 74values updated at this time. Note that this means `common.port` refers 75to the port of the most recent listening server. Each server will maintain 76its own `mr.port`. 77 78Any errors emitted by the server while it was coming online will result in a 79promise rejection. 80 81## mr.mock(method, url, respondWith) → this 82 83Adds a new route that matches `method` (should be all caps) and `url`. 84 85`respondWith` can be: 86 87* A function, that takes `(request, response)` as arguments and calls 88 [`response` methods](https://nodejs.org/api/http.html#http_class_http_serverresponse) 89 to do what it wants. Does not have a return value. This function may be 90 async (the response isn't complete till its stream completes), typically 91 either because you piped something into it or called `response.end()`. 92* An array of `[statusCode, responseBody]`. `responseBody` may be a string or 93 an object. Objects are serialized with `JSON.stringify`. 94 95## mr.close() → Promise(mr) 96 97Calls `mr.reset()` to clear the mocks. 98 99Calls `.close()` on the http server. The promise resolves when the http 100server completes closing. Any errors while the http server was closing will 101result in a rejection. If running with `keepNodeAlive` set this call 102is required for node to exit the event loop. 103 104# Events 105 106## mr.on('error', err => { … }) 107 108Error events from the http server are forwarded to the associated fake 109registry instance. 110 111The exception to this is while the `mr.listen()` and `mr.close()` promises 112are waiting to complete. Those promises capture any errors during their duration 113and turn them into rejections. (Errors during those phases are very rare.) 114 115# Compat Interface 116 117## Differences 118 119### Ports 120 121You aren't guaranteed to get the port you ask for. If the port you asked 122for is in use, it will be incremented until an available port is found. 123 124`server.port` and `server.registry` contain the port that was actually selected. 125 126For compatibility reasons: 127 128`common.port` and `common.registry` will contain the port of the most recent 129instance of FakeRegistry. Usually these there is only one instance and so 130this has the same value as the per-server attributes. 131 132This means that if your fixtures make use of the port or server address they 133need to be configured _after_ you construct 134 135### Request Bodies 136 137Request bodies are NOT matched against. Two routes for the same URL but different 138request bodies will overwrite one another. 139 140### Call Count Assertions 141 142That is, things like `twice()` that assert that the end point will be hit 143two times are not supported. This library does not provide any assertions, 144just a barebones http server. 145 146### Default Route Behavior 147 148If no route can be found then a `404` response will be provided. 149 150## Construction 151 152const common = require('../common-tap.js') 153const mr = common.fakeRegistry.compat 154 155### mr(options[, callback]) → Promise(server) 156 157Construct a new mock server. Hybrid, callback/promise constructor. Options 158are `port` and `keepNodeAlive`. `keepNodeAlive` defaults to `true` for 159compatibility mode and the default value of port comes from `common.port`. 160 161### done() 162 163Resets all of the configured mocks. 164 165### close() 166 167Calls `this.reset()` and `this.server.close()`. To reopen this instance use 168`this.listen()`. 169 170### filteringRequestBody() 171 172Does nothing. Bodies are never matched when routing anyway so this is unnecessary. 173 174### get(url) → MockReply 175### delete(url) → MockReply 176### post(url, body) → MockReply 177### put(url, body) → MockReply 178 179Begins to add a route for an HTTP method and URL combo. Does not actually 180add it till `reply()` is called on the returned object. 181 182Note that the body argument for post and put is always ignored. 183 184## MockReply methods 185 186### twice() → this 187 188Does nothing. Call count assertions are not supported. 189 190### reply(status, responseBody) 191 192Actually adds the route, set to reply with the associated status and 193responseBody. 194 195Currently no mime-types are set. 196 197If `responseBody` is `typeof === 'object'` then `JSON.stringify()` will be 198called on it to serialize it, otherwise `String()` will be used. 199