Skip to content

Commit

Permalink
feat: Allow optionally() to be called with a value, specifying if the…
Browse files Browse the repository at this point in the history
… mock should be optional

When setting up a mock, you can call `optionally()` to specify
that the mock is __optional__, meaning that it won't be
returned in `nock.pendingMocks()` and it won't affect the
result of `nock.isDone()`.

You have to call `optionally()` before you call a method like
`reply()` to specify the response, because at that point the
mock is persisted and you can no longer touch it (that is to
say, `reply()` returns the scope rather than the mock).

This part of Nock's API makes life painful if you want to
have a mock which is configurable as either optional or
required. The way that mocks are chained together makes
your code long-winded and hard to read:

```js
const getLoginMock = ({ optional = false }) => {
  const mock = nock('https://supercoolauthservice.com')
    .post('/login');

  if (optional) {
    mock = mock.optionally();
  }

  mock.reply(200);
}
```

This change makes life simpler, allowing you to specify
when you call `optionally()` whether you want the mock
to be optional or not:

```js
const getLoginMock = ({ optional = false }) => {
  nock('https://supercoolauthservice.com')
    .post('/login')
    .optionally(optional)
    .reply(200);
}
```
  • Loading branch information
Tim Rogers authored and timrogers committed Aug 7, 2018
1 parent 50ab208 commit d8a2606
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 2 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,19 @@ example.pendingMocks() // []

example.get("/pathB").optionally().reply(200);
example.pendingMocks() // []

// You can also pass a boolean argument to `optionally()`. This
// is useful if you want to conditionally make a mocked request
// optional.
var getMock = function(optional) {
return example.get("/pathC").optionally(optional).reply(200);
}

getMock(true);
example.pendingMocks() // []
getMock(false);
example.pendingMocks() // ["GET http://example.com:80/pathC"]

```

### Allow __unmocked__ requests on a mocked hostname
Expand Down
8 changes: 6 additions & 2 deletions lib/interceptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ function Interceptor(scope, uri, method, requestBody, interceptorOptions) {
this.optional = false;
}

Interceptor.prototype.optionally = function optionally() {
this.optional = true;
Interceptor.prototype.optionally = function optionally(value) {
// The default behaviour of optionally() with no arguments is to make the mock optional.
value = (typeof value === 'undefined') ? true : value;

this.optional = value;

return this;
}

Expand Down
21 changes: 21 additions & 0 deletions tests/test_intercept.js
Original file line number Diff line number Diff line change
Expand Up @@ -2414,6 +2414,27 @@ test('pending mocks doesn\'t include optional mocks', function(t) {
t.end();
});

test('calling optionally(true) on a mock makes it optional', function (t) {
nock('http://example.com')
.get('/nonexistent')
.optionally(true)
.reply(200);

t.deepEqual(nock.pendingMocks(), []);
t.end();
});

test('calling optionally(false) on a mock leaves it as required', function(t) {
nock('http://example.com')
.get('/nonexistent')
.optionally(false)
.reply(200);

t.notEqual(nock.pendingMocks(), []);
nock.cleanAll();
t.end();
});

test('optional mocks are still functional', function(t) {
nock('http://example.com')
.get('/abc')
Expand Down

0 comments on commit d8a2606

Please sign in to comment.