# FakeRegistry

This is a replacement for npm-registry-mock in times where its fixtures are
not used.  (Adding support for its standard fixtures is TODO, but should be
straightforward—tacks-ify them and call `mr.mock…`

# Usage

The intent is for this to be a drop in replacement for npm-registry-mock
(and by extension hock).  New scripts will be better served using its native
interface, however.

# Main Interface

## Logging

All requests the mock registry receives are logged at the `http` level. You can
see these by running your tests with:

```
npm --loglevel=http run tap test/tap/name-of-test.js
```

Or directly with:

```
npm_config_loglevel=http node test/tap/name-of-test.js
```

## Construction

Ordinarily there's no reason to construct more than one FakeRegistyr object
at a time, as it can be entirely reset between tests, so best practice
would be to use its singleton.

```
const common = require('../common-tap.js')
const mr = common.fakeRegistry
```

If you have need of multiple registries at the same time, you can construct
them by hand:

```
const common = require('../common-tap.js')
const FakeRegistry = common.fakeRegistry.FakeRegistry
const mr = new FakeRegistry(opts)
```

## new FakeRegistry(opts)

Valid options are:

* `opts.port` is the first port to try when looking for an available port.  If it
  is unavialable it will be incremented until one available is found.

  The default value of `port` is taken from `common.npm`.

* `opts.keepNodeAlive` will instruct FakeRegistry to not unref the
  underlying server.

## mr.reset() → this

Reset all mocks to their default values. Further requests

## mr.listen() → Promise(mr)

Start listening for connections.  The promise resolves when the server is
online and ready to accept connections.

`mr.port` and `mr.registry` contain the port that was actually selected.

To ease compatibility, `common` will also have its `port` and `registry`
values updated at this time. Note that this means `common.port` refers
to the port of the most recent listening server. Each server will maintain
its own `mr.port`.

Any errors emitted by the server while it was coming online will result in a
promise rejection.

## mr.mock(method, url, respondWith) → this

Adds a new route that matches `method` (should be all caps) and `url`.

`respondWith` can be:

* A function, that takes `(request, response)` as arguments and calls
  [`response` methods](https://nodejs.org/api/http.html#http_class_http_serverresponse)
  to do what it wants.  Does not have a return value.  This function may be
  async (the response isn't complete till its stream completes), typically
  either because you piped something into it or called `response.end()`.
* An array of `[statusCode, responseBody]`. `responseBody` may be a string or
  an object. Objects are serialized with `JSON.stringify`.

## mr.close() → Promise(mr)

Calls `mr.reset()` to clear the mocks.

Calls `.close()` on the http server.  The promise resolves when the http
server completes closing.  Any errors while the http server was closing will
result in a rejection. If running with `keepNodeAlive` set this call
is required for node to exit the event loop.

# Events

## mr.on('error', err => { … })

Error events from the http server are forwarded to the associated fake
registry instance.

The exception to this is while the `mr.listen()` and `mr.close()` promises
are waiting to complete. Those promises capture any errors during their duration
and turn them into rejections. (Errors during those phases are very rare.)

# Compat Interface

## Differences

### Ports

You aren't guaranteed to get the port you ask for.  If the port you asked
for is in use, it will be incremented until an available port is found.

`server.port` and `server.registry` contain the port that was actually selected.

For compatibility reasons:

`common.port` and `common.registry` will contain the port of the most recent
instance of FakeRegistry.  Usually these there is only one instance and so
this has the same value as the per-server attributes.

This means that if your fixtures make use of the port or server address they
need to be configured _after_ you construct

### Request Bodies

Request bodies are NOT matched against. Two routes for the same URL but different
request bodies will overwrite one another.

### Call Count Assertions

That is, things like `twice()` that assert that the end point will be hit
two times are not supported.  This library does not provide any assertions,
just a barebones http server.

### Default Route Behavior

If no route can be found then a `404` response will be provided.

## Construction

const common = require('../common-tap.js')
const mr = common.fakeRegistry.compat

### mr(options[, callback]) → Promise(server)

Construct a new mock server.  Hybrid, callback/promise constructor. Options
are `port` and `keepNodeAlive`.  `keepNodeAlive` defaults to `true` for
compatibility mode and the default value of port comes from `common.port`.

### done()

Resets all of the configured mocks. 

### close()

Calls `this.reset()` and `this.server.close()`.  To reopen this instance use
`this.listen()`.

### filteringRequestBody()

Does nothing. Bodies are never matched when routing anyway so this is unnecessary.

### get(url) → MockReply
### delete(url) → MockReply
### post(url, body) → MockReply
### put(url, body) → MockReply

Begins to add a route for an HTTP method and URL combo.  Does not actually
add it till `reply()` is called on the returned object.

Note that the body argument for post and put is always ignored.

## MockReply methods

### twice() → this

Does nothing. Call count assertions are not supported.

### reply(status, responseBody)

Actually adds the route, set to reply with the associated status and
responseBody.

Currently no mime-types are set.

If `responseBody` is `typeof === 'object'` then `JSON.stringify()` will be
called on it to serialize it, otherwise `String()` will be used.
