UNPKG

42.3 kBMarkdownView Raw
1# Nock
2
3[![Build Status](https://travis-ci.org/nock/nock.svg?branch=master)](https://travis-ci.org/nock/nock)
4[![Coverage Status](https://coveralls.io/repos/github/nock/nock/badge.svg?branch=master)](https://coveralls.io/github/nock/nock?branch=master)
5[![Greenkeeper](https://badges.greenkeeper.io/nock/nock.svg)](https://greenkeeper.io/)
6
7> HTTP server mocking and expectations library for Node.js
8
9Nock can be used to test modules that perform HTTP requests in isolation.
10
11For instance, if a module performs HTTP requests to a CouchDB server or makes HTTP requests to the Amazon API, you can test that module in isolation.
12
13**Table of Contents**
14
15<!-- toc -->
16
17- [How does it work?](#how-does-it-work)
18- [Install](#install)
19 * [Node version support](#node-version-support)
20- [Usage](#usage)
21 * [READ THIS! - About interceptors](#read-this---about-interceptors)
22 * [Specifying hostname](#specifying-hostname)
23 * [Specifying path](#specifying-path)
24 * [Specifying request body](#specifying-request-body)
25 * [Specifying request query string](#specifying-request-query-string)
26 * [Specifying replies](#specifying-replies)
27 - [Access original request and headers](#access-original-request-and-headers)
28 + [Replying with errors](#replying-with-errors)
29 * [Specifying headers](#specifying-headers)
30 + [Header field names are case-insensitive](#header-field-names-are-case-insensitive)
31 + [Specifying Request Headers](#specifying-request-headers)
32 + [Specifying Reply Headers](#specifying-reply-headers)
33 + [Default Reply Headers](#default-reply-headers)
34 + [Including Content-Length Header Automatically](#including-content-length-header-automatically)
35 + [Including Date Header Automatically](#including-date-header-automatically)
36 * [HTTP Verbs](#http-verbs)
37 * [Support for HTTP and HTTPS](#support-for-http-and-https)
38 * [Non-standard ports](#non-standard-ports)
39 * [Repeat response n times](#repeat-response-n-times)
40 * [Delay the response body](#delay-the-response-body)
41 * [Delay the response](#delay-the-response)
42 * [Delay the connection](#delay-the-connection)
43 * [Socket timeout](#socket-timeout)
44 * [Chaining](#chaining)
45 * [Scope filtering](#scope-filtering)
46 * [Path filtering](#path-filtering)
47 * [Request Body filtering](#request-body-filtering)
48 * [Request Headers Matching](#request-headers-matching)
49 * [Optional Requests](#optional-requests)
50 * [Allow __unmocked__ requests on a mocked hostname](#allow-__unmocked__-requests-on-a-mocked-hostname)
51- [Expectations](#expectations)
52 * [.isDone()](#isdone)
53 * [.cleanAll()](#cleanall)
54 * [.persist()](#persist)
55 * [.pendingMocks()](#pendingmocks)
56 * [.activeMocks()](#activemocks)
57 * [.isActive()](#isactive)
58- [Logging](#logging)
59- [Restoring](#restoring)
60- [Activating](#activating)
61- [Turning Nock Off (experimental!)](#turning-nock-off-experimental)
62- [Enable/Disable real HTTP request](#enabledisable-real-http-request)
63- [Recording](#recording)
64 * [`dont_print` option](#dont_print-option)
65 * [`output_objects` option](#output_objects-option)
66 * [`enable_reqheaders_recording` option](#enable_reqheaders_recording-option)
67 * [`logging` option](#logging-option)
68 * [`use_separator` option](#use_separator-option)
69 * [.removeInterceptor()](#removeinterceptor)
70- [Events](#events)
71 * [Global no match event](#global-no-match-event)
72- [Nock Back](#nock-back)
73 * [Setup](#setup)
74 + [Options](#options)
75 * [Usage](#usage-1)
76 + [Options](#options-1)
77 + [Modes](#modes)
78- [Debugging](#debugging)
79- [PROTIP](#protip)
80- [Contributing](#contributing)
81- [License](#license)
82
83<!-- tocstop -->
84
85## How does it work?
86
87Nock works by overriding Node's `http.request` function. Also, it overrides `http.ClientRequest` too to cover for modules that use it directly.
88
89## Install
90
91```sh
92$ npm install --save nock
93```
94
95### Node version support
96
97| node | nock |
98|---|---|
99| 0.10 | up to 8.x |
100| 0.11 | up to 8.x |
101| 0.12 | up to 8.x |
102| 4 | 9.x |
103| 5 | up to 8.x |
104| 6 | 9.x |
105
106## Usage
107
108On your test, you can setup your mocking object like this:
109
110```js
111var nock = require('nock');
112
113var couchdb = nock('http://myapp.iriscouch.com')
114 .get('/users/1')
115 .reply(200, {
116 _id: '123ABC',
117 _rev: '946B7D1C',
118 username: 'pgte',
119 email: 'pedro.teixeira@gmail.com'
120 });
121```
122
123This setup says that we will intercept every HTTP call to `http://myapp.iriscouch.com`.
124
125It will intercept an HTTP GET request to '/users/1' and reply with a status 200, and the body will contain a user representation in JSON.
126
127Then the test can call the module, and the module will do the HTTP requests.
128
129### READ THIS! - About interceptors
130
131When you setup an interceptor for a URL and that interceptor is used, it is removed from the interceptor list.
132This means that you can intercept 2 or more calls to the same URL and return different things on each of them.
133It also means that you must setup one interceptor for each request you are going to have, otherwise nock will throw an error because that URL was not present in the interceptor list.
134If you don’t want interceptors to be removed as they are used, you can use the [.persist()](#persist) method.
135
136### Specifying hostname
137
138The request hostname can be a string or a RegExp.
139
140```js
141var scope = nock('http://www.example.com')
142 .get('/resource')
143 .reply(200, 'domain matched');
144```
145
146```js
147var scope = nock(/example\.com/)
148 .get('/resource')
149 .reply(200, 'domain regex matched');
150```
151
152> Note: You can choose to include or not the protocol in the hostname matching.
153
154### Specifying path
155
156The request path can be a string, a RegExp or a filter function and you can use any [HTTP verb](#http-verbs).
157
158Using a string:
159
160```js
161var scope = nock('http://www.example.com')
162 .get('/resource')
163 .reply(200, 'path matched');
164```
165
166Using a regular expression:
167
168```js
169var scope = nock('http://www.example.com')
170 .get(/source$/)
171 .reply(200, 'path using regex matched');
172```
173
174Using a function:
175
176```js
177var scope = nock('http://www.example.com')
178 .get(function(uri) {
179 return uri.indexOf('cats') >= 0;
180 })
181 .reply(200, 'path using function matched');
182```
183
184### Specifying request body
185
186You can specify the request body to be matched as the second argument to the `get`, `post`, `put` or `delete` specifications. There are five types of second argument allowed:
187
188**String**: nock will exact match the stringified request body with the provided string
189
190```js
191nock('http://www.example.com')
192 .post('/login', 'username=pgte&password=123456')
193 .reply(200, { id: '123ABC' });
194```
195
196**Buffer**: nock will exact match the stringified request body with the provided buffer
197
198```js
199nock('http://www.example.com')
200 .post('/login', Buffer.from([0xff, 0x11]))
201 .reply(200, { id: '123ABC' });
202```
203
204**RegExp**: nock will test the stringified request body against the provided RegExp
205
206```js
207nock('http://www.example.com')
208 .post('/login', /username=\w+/gi)
209 .reply(200, { id: '123ABC' });
210```
211
212**JSON object**: nock will exact match the request body with the provided object. In order to increase flexibility, nock also supports RegExp as an attribute value for the keys:
213
214```js
215nock('http://www.example.com')
216 .post('/login', { username: 'pgte', password: /.+/i })
217 .reply(200, { id: '123ABC' });
218```
219
220**Function**: nock will evaluate the function providing the request body object as first argument. Return true if it should be considered a match:
221
222```js
223nock('http://www.example.com')
224 .post('/login', function(body) {
225 return body.username && body.password;
226 })
227 .reply(200, { id: '123ABC' });
228```
229
230In case you need to perform a partial matching on a complex, nested request body you should have a look at libraries like [lodash.matches](https://lodash.com/docs/#matches). Indeed, partial matching can be achieved as:
231
232```js
233nock('http://www.example.com')
234 .post('/user', _.matches({ address: { country: 'US' } }))
235 .reply(200, { id: '123ABC' });
236```
237
238
239### Specifying request query string
240
241Nock understands query strings. Instead of placing the entire URL, you can specify the query part as an object:
242
243```js
244nock('http://example.com')
245 .get('/users')
246 .query({name: 'pedro', surname: 'teixeira'})
247 .reply(200, {results: [{id: 'pgte'}]});
248```
249
250Nock supports array-style/object-style query parameters. The encoding format matches with request module.
251
252```js
253nock('http://example.com')
254 .get('/users')
255 .query({
256 names: ['alice', 'bob'],
257 tags: {
258 alice: ['admin', 'tester'],
259 bob: ['tester']
260 }
261 })
262 .reply(200, {results: [{id: 'pgte'}]});
263```
264
265Nock supports passing a function to query. The function determines if the actual query matches or not.
266
267```js
268nock('http://example.com')
269 .get('/users')
270 .query(function(actualQueryObject){
271 // do some compare with the actual Query Object
272 // return true for matched
273 // return false for not matched
274 return true;
275 })
276 .reply(200, {results: [{id: 'pgte'}]});
277```
278
279To mock the entire url regardless of the passed query string:
280
281```js
282nock('http://example.com')
283 .get('/users')
284 .query(true)
285 .reply(200, {results: [{id: 'pgte'}]});
286```
287
288### Specifying replies
289
290You can specify the return status code for a path on the first argument of reply like this:
291
292```js
293var scope = nock('http://myapp.iriscouch.com')
294 .get('/users/1')
295 .reply(404);
296```
297
298You can also specify the reply body as a string:
299
300```js
301var scope = nock('http://www.google.com')
302 .get('/')
303 .reply(200, 'Hello from Google!');
304```
305
306or as a JSON-encoded object:
307
308```js
309var scope = nock('http://myapp.iriscouch.com')
310 .get('/')
311 .reply(200, {
312 username: 'pgte',
313 email: 'pedro.teixeira@gmail.com',
314 _id: '4324243fsd'
315 });
316```
317
318or even as a file:
319
320```js
321var scope = nock('http://myapp.iriscouch.com')
322 .get('/')
323 .replyWithFile(200, __dirname + '/replies/user.json', { 'Content-Type': 'application/json' });
324```
325
326Instead of an object or a buffer you can also pass in a callback to be evaluated for the value of the response body:
327
328```js
329var scope = nock('http://www.google.com')
330 .filteringRequestBody(/.*/, '*')
331 .post('/echo', '*')
332 .reply(201, function(uri, requestBody) {
333 return requestBody;
334 });
335```
336
337An asynchronous function that gets an error-first callback as last argument also works:
338
339```js
340var scope = nock('http://www.google.com')
341 .filteringRequestBody(/.*/, '*')
342 .post('/echo', '*')
343 .reply(201, function(uri, requestBody, cb) {
344 fs.readFile('cat-poems.txt' , cb); // Error-first callback
345 });
346```
347
348> Note: When using a callback, if you call back with an error as first argument, that error will be sent in the response body, with a 500 HTTP response status code.
349
350You can also return the status code and body using just one function:
351
352```js
353var scope = nock('http://www.google.com')
354 .filteringRequestBody(/.*/, '*')
355 .post('/echo', '*')
356 .reply(function(uri, requestBody) {
357 return [
358 201,
359 'THIS IS THE REPLY BODY',
360 {'header': 'value'} // optional headers
361 ];
362 });
363```
364
365or, use an error-first callback that also gets the status code:
366
367```js
368var scope = nock('http://www.google.com')
369 .filteringRequestBody(/.*/, '*')
370 .post('/echo', '*')
371 .reply(function(uri, requestBody, cb) {
372 setTimeout(function() {
373 cb(null, [201, 'THIS IS THE REPLY BODY'])
374 }, 1e3);
375 });
376```
377
378A Stream works too:
379```js
380var scope = nock('http://www.google.com')
381 .get('/cat-poems')
382 .reply(200, function(uri, requestBody) {
383 return fs.createReadStream('cat-poems.txt');
384 });
385```
386
387##### Access original request and headers
388
389If you're using the reply callback style, you can access the original client request using `this.req` like this:
390
391```js
392var scope = nock('http://www.google.com')
393 .get('/cat-poems')
394 .reply(function(uri, requestBody) {
395 console.log('path:', this.req.path);
396 console.log('headers:', this.req.headers);
397 // ...
398 });
399```
400
401#### Replying with errors
402
403You can reply with an error like this:
404
405```js
406nock('http://www.google.com')
407 .get('/cat-poems')
408 .replyWithError('something awful happened');
409```
410
411JSON error responses are allowed too:
412
413```js
414nock('http://www.google.com')
415 .get('/cat-poems')
416 .replyWithError({'message': 'something awful happened', 'code': 'AWFUL_ERROR'});
417```
418
419> Note: This will emit an `error` event on the `request` object, not the reply.
420
421
422### Specifying headers
423
424#### Header field names are case-insensitive
425
426Per [HTTP/1.1 4.2 Message Headers](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) specification, all message headers are case insensitive and thus internally Nock uses lower-case for all field names even if some other combination of cases was specified either in mocking specification or in mocked requests themselves.
427
428#### Specifying Request Headers
429
430You can specify the request headers like this:
431
432```js
433var scope = nock('http://www.example.com', {
434 reqheaders: {
435 'authorization': 'Basic Auth'
436 }
437 })
438 .get('/')
439 .reply(200);
440```
441
442Or you can use a Regular Expression or Function check the header values. The function will be
443passed the header value.
444
445```js
446var scope = nock('http://www.example.com', {
447 reqheaders: {
448 'X-My-Headers': function (headerValue) {
449 if (headerValue) {
450 return true;
451 }
452 return false;
453 },
454 'X-My-Awesome-Header': /Awesome/i
455 }
456 })
457 .get('/')
458 .reply(200);
459```
460
461If `reqheaders` is not specified or if `host` is not part of it, Nock will automatically add `host` value to request header.
462
463If no request headers are specified for mocking then Nock will automatically skip matching of request headers. Since `host` header is a special case which may get automatically inserted by Nock, its matching is skipped unless it was *also* specified in the request being mocked.
464
465You can also have Nock fail the request if certain headers are present:
466
467```js
468var scope = nock('http://www.example.com', {
469 badheaders: ['cookie', 'x-forwarded-for']
470 })
471 .get('/')
472 .reply(200);
473```
474
475When invoked with this option, Nock will not match the request if any of the `badheaders` are present.
476
477Basic authentication can be specified as follows:
478
479```js
480var scope = nock('http://www.example.com')
481 .get('/')
482 .basicAuth({
483 user: 'john',
484 pass: 'doe'
485 })
486 .reply(200);
487```
488
489#### Specifying Reply Headers
490
491You can specify the reply headers like this:
492
493```js
494var scope = nock('http://www.headdy.com')
495 .get('/')
496 .reply(200, 'Hello World!', {
497 'X-My-Headers': 'My Header value'
498 });
499```
500
501Or you can use a function to generate the headers values. The function will be
502passed the request, response, and body (if available). The body will be either a
503buffer, a stream, or undefined.
504
505```js
506var scope = nock('http://www.headdy.com')
507 .get('/')
508 .reply(200, 'Hello World!', {
509 'X-My-Headers': function (req, res, body) {
510 return body.toString();
511 }
512 });
513```
514
515#### Default Reply Headers
516
517You can also specify default reply headers for all responses like this:
518
519```js
520var scope = nock('http://www.headdy.com')
521 .defaultReplyHeaders({
522 'X-Powered-By': 'Rails',
523 'Content-Type': 'application/json'
524 })
525 .get('/')
526 .reply(200, 'The default headers should come too');
527```
528
529Or you can use a function to generate the default headers values:
530
531```js
532var scope = nock('http://www.headdy.com')
533 .defaultReplyHeaders({
534 'Content-Length': function (req, res, body) {
535 return body.length;
536 }
537 })
538 .get('/')
539 .reply(200, 'The default headers should come too');
540```
541
542#### Including Content-Length Header Automatically
543
544When using `scope.reply()` to set a response body manually, you can have the
545`Content-Length` header calculated automatically.
546
547```js
548var scope = nock('http://www.headdy.com')
549 .replyContentLength()
550 .get('/')
551 .reply(200, { hello: 'world' });
552```
553
554**NOTE:** this does not work with streams or other advanced means of specifying
555the reply body.
556
557#### Including Date Header Automatically
558
559You can automatically append a `Date` header to your mock reply:
560
561```js
562var scope = nock('http://www.headdy.com')
563 .replyDate(new Date(2015, 0, 1)) // defaults to now, must use a Date object
564 .get('/')
565 .reply(200, { hello: 'world' });
566```
567
568### HTTP Verbs
569
570Nock supports any HTTP verb, and it has convenience methods for the GET, POST, PUT, HEAD, DELETE, PATCH and MERGE HTTP verbs.
571
572You can intercept any HTTP verb using `.intercept(path, verb [, requestBody [, options]])`:
573
574```js
575var scope = nock('http://my.domain.com')
576 .intercept('/path', 'PATCH')
577 .reply(304);
578```
579
580### Support for HTTP and HTTPS
581
582By default nock assumes HTTP. If you need to use HTTPS you can specify the `https://` prefix like this:
583
584```js
585var scope = nock('https://secure.my.server.com')
586 // ...
587```
588
589### Non-standard ports
590
591You are able to specify a non-standard port like this:
592
593```js
594var scope = nock('http://my.server.com:8081')
595 ...
596```
597
598### Repeat response n times
599
600You are able to specify the number of times to repeat the same response.
601
602```js
603nock('http://zombo.com').get('/').times(4).reply(200, 'Ok');
604
605http.get('http://zombo.com/'); // respond body "Ok"
606http.get('http://zombo.com/'); // respond body "Ok"
607http.get('http://zombo.com/'); // respond body "Ok"
608http.get('http://zombo.com/'); // respond body "Ok"
609http.get('http://zombo.com/'); // respond with zombo.com result
610```
611
612Sugar syntax
613
614```js
615nock('http://zombo.com').get('/').once().reply(200, 'Ok');
616nock('http://zombo.com').get('/').twice().reply(200, 'Ok');
617nock('http://zombo.com').get('/').thrice().reply(200, 'Ok');
618```
619
620### Delay the response body
621You are able to specify the number of milliseconds that the response body should be delayed. Response header will be replied immediately.
622`delayBody(1000)` is equivalent to `delay({body: 1000})`.
623
624
625```js
626nock('http://my.server.com')
627 .get('/')
628 .delayBody(2000) // 2 seconds
629 .reply(200, '<html></html>')
630```
631
632NOTE: the [`'response'`](http://nodejs.org/api/http.html#http_event_response) event will occur immediately, but the [IncomingMessage](http://nodejs.org/api/http.html#http_http_incomingmessage) will not emit it's `'end'` event until after the delay.
633
634### Delay the response
635
636You are able to specify the number of milliseconds that your reply should be delayed.
637
638```js
639nock('http://my.server.com')
640 .get('/')
641 .delay(2000) // 2 seconds delay will be applied to the response header.
642 .reply(200, '<html></html>')
643```
644
645`delay()` could also be used as
646
647 ```
648 delay({
649 head: headDelayInMs,
650 body: bodyDelayInMs
651 })
652 ```
653
654 for example
655
656```js
657nock('http://my.server.com')
658 .get('/')
659 .delay({
660 head: 2000, // header will be delayed for 2 seconds, i.e. the whole response will be delayed for 2 seconds.
661 body: 3000 // body will be delayed for another 3 seconds after header is sent out.
662 })
663 .reply(200, '<html></html>')
664```
665
666### Delay the connection
667
668`delayConnection(1000)` is equivalent to `delay({head: 1000})`.
669
670### Socket timeout
671
672You are able to specify the number of milliseconds that your connection should be idle, to simulate a socket timeout.
673
674```js
675nock('http://my.server.com')
676 .get('/')
677 .socketDelay(2000) // 2 seconds
678 .reply(200, '<html></html>')
679```
680
681To test a request like the following:
682
683```js
684req = http.request('http://my.server.com', function(res) {
685 ...
686});
687req.setTimeout(1000, function() {
688 req.abort();
689});
690req.end();
691```
692
693NOTE: the timeout will be fired immediately, and will not leave the simulated connection idle for the specified period of time.
694
695### Chaining
696
697You can chain behaviour like this:
698
699```js
700var scope = nock('http://myapp.iriscouch.com')
701 .get('/users/1')
702 .reply(404)
703 .post('/users', {
704 username: 'pgte',
705 email: 'pedro.teixeira@gmail.com'
706 })
707 .reply(201, {
708 ok: true,
709 id: '123ABC',
710 rev: '946B7D1C'
711 })
712 .get('/users/123ABC')
713 .reply(200, {
714 _id: '123ABC',
715 _rev: '946B7D1C',
716 username: 'pgte',
717 email: 'pedro.teixeira@gmail.com'
718 });
719```
720
721### Scope filtering
722
723You can filter the scope (protocol, domain or port) of nock through a function. The filtering function is accepted at the `filteringScope` field of the `options` argument.
724
725This can be useful if you have a node module that randomly changes subdomains to which it sends requests, e.g., the Dropbox node module behaves like this.
726
727```js
728var scope = nock('https://api.dropbox.com', {
729 filteringScope: function(scope) {
730 return /^https:\/\/api[0-9]*.dropbox.com/.test(scope);
731 }
732 })
733 .get('/1/metadata/auto/Photos?include_deleted=false&list=true')
734 .reply(200);
735```
736
737### Path filtering
738
739You can also filter the URLs based on a function.
740
741This can be useful, for instance, if you have random or time-dependent data in your URL.
742
743You can use a regexp for replacement, just like String.prototype.replace:
744
745```js
746var scope = nock('http://api.myservice.com')
747 .filteringPath(/password=[^&]*/g, 'password=XXX')
748 .get('/users/1?password=XXX')
749 .reply(200, 'user');
750```
751
752Or you can use a function:
753
754```js
755var scope = nock('http://api.myservice.com')
756 .filteringPath(function(path) {
757 return '/ABC';
758 })
759 .get('/ABC')
760 .reply(200, 'user');
761```
762
763Note that `scope.filteringPath` is not cumulative: it should only be used once per scope.
764
765### Request Body filtering
766
767You can also filter the request body based on a function.
768
769This can be useful, for instance, if you have random or time-dependent data in your request body.
770
771You can use a regexp for replacement, just like String.prototype.replace:
772
773```js
774var scope = nock('http://api.myservice.com')
775 .filteringRequestBody(/password=[^&]*/g, 'password=XXX')
776 .post('/users/1', 'data=ABC&password=XXX')
777 .reply(201, 'OK');
778```
779
780Or you can use a function to transform the body:
781
782```js
783var scope = nock('http://api.myservice.com')
784 .filteringRequestBody(function(body) {
785 return 'ABC';
786 })
787 .post('/', 'ABC')
788 .reply(201, 'OK');
789```
790
791### Request Headers Matching
792
793If you need to match requests only if certain request headers match, you can.
794
795```js
796var scope = nock('http://api.myservice.com')
797 .matchHeader('accept', 'application/json')
798 .get('/')
799 .reply(200, {
800 data: 'hello world'
801 })
802```
803
804You can also use a regexp for the header body.
805
806```js
807var scope = nock('http://api.myservice.com')
808 .matchHeader('User-Agent', /Mozilla\/.*/)
809 .get('/')
810 .reply(200, {
811 data: 'hello world'
812 })
813```
814
815You can also use a function for the header body.
816
817```js
818var scope = nock('http://api.myservice.com')
819 .matchHeader('content-length', function (val) {
820 return val >= 1000;
821 })
822 .get('/')
823 .reply(200, {
824 data: 'hello world'
825 })
826```
827
828### Optional Requests
829
830By default every mocked request is expected to be made exactly once, and until it is it'll appear in `scope.pendingMocks()`, and `scope.isDone()` will return false (see [expectations](#expectations)). In many cases this is fine, but in some (especially cross-test setup code) it's useful to be able to mock a request that may or may not happen. You can do this with `optionally()`. Optional requests are consumed just like normal ones once matched, but they do not appear in `pendingMocks()`, and `isDone()` will return true for scopes with only optional requests pending.
831
832```js
833var example = nock("http://example.com");
834example.pendingMocks() // []
835example.get("/pathA").reply(200);
836example.pendingMocks() // ["GET http://example.com:80/path"]
837
838// ...After a request to example.com/pathA:
839example.pendingMocks() // []
840
841example.get("/pathB").optionally().reply(200);
842example.pendingMocks() // []
843
844// You can also pass a boolean argument to `optionally()`. This
845// is useful if you want to conditionally make a mocked request
846// optional.
847var getMock = function(optional) {
848 return example.get("/pathC").optionally(optional).reply(200);
849}
850
851getMock(true);
852example.pendingMocks() // []
853getMock(false);
854example.pendingMocks() // ["GET http://example.com:80/pathC"]
855
856```
857
858### Allow __unmocked__ requests on a mocked hostname
859
860If you need some request on the same host name to be mocked and some others to **really** go through the HTTP stack, you can use the `allowUnmocked` option like this:
861
862```js
863options = {allowUnmocked: true};
864var scope = nock('http://my.existing.service.com', options)
865 .get('/my/url')
866 .reply(200, 'OK!');
867
868 // GET /my/url => goes through nock
869 // GET /other/url => actually makes request to the server
870```
871
872> Note: When applying `{allowUnmocked: true}`, if the request is made to the real server, no interceptor is removed.
873
874## Expectations
875
876Every time an HTTP request is performed for a scope that is mocked, Nock expects to find a handler for it. If it doesn't, it will throw an error.
877
878Calls to nock() return a scope which you can assert by calling `scope.done()`. This will assert that all specified calls on that scope were performed.
879
880Example:
881
882```js
883var google = nock('http://google.com')
884 .get('/')
885 .reply(200, 'Hello from Google!');
886
887// do some stuff
888
889setTimeout(function() {
890 google.done(); // will throw an assertion error if meanwhile a "GET http://google.com" was not performed.
891}, 5000);
892```
893
894### .isDone()
895
896You can call `isDone()` on a single expectation to determine if the expectation was met:
897
898```js
899var scope = nock('http://google.com')
900 .get('/')
901 .reply(200);
902
903scope.isDone(); // will return false
904```
905
906It is also available in the global scope, which will determine if all expectations have been met:
907
908```js
909nock.isDone();
910```
911
912### .cleanAll()
913
914You can cleanup all the prepared mocks (could be useful to cleanup some state after a failed test) like this:
915
916```js
917nock.cleanAll();
918```
919### .persist()
920
921You can make all the interceptors for a scope persist by calling `.persist()` on it:
922
923```js
924var scope = nock('http://persisssists.con')
925 .persist()
926 .get('/')
927 .reply(200, 'Persisting all the way');
928```
929
930Note that while a persisted scope will always intercept the requests, it is considered "done" after the first interception.
931
932If you want to stop persisting a persistent nock you can call `persist(false)`:
933
934```js
935var scope = nock('http://example.com').persist().get('/').reply(200, 'ok');
936// do some tests ...
937scope.persist(false);
938```
939
940### .pendingMocks()
941
942If a scope is not done, you can inspect the scope to infer which ones are still pending using the `scope.pendingMocks()` function:
943
944```js
945if (!scope.isDone()) {
946 console.error('pending mocks: %j', scope.pendingMocks());
947}
948```
949
950It is also available in the global scope:
951
952```js
953console.error('pending mocks: %j', nock.pendingMocks());
954```
955
956### .activeMocks()
957
958You can see every mock that is currently active (i.e. might potentially reply to requests) in a scope using `scope.activeMocks()`. A mock is active if it is pending, optional but not yet completed, or persisted. Mocks that have intercepted their requests and are no longer doing anything are the only mocks which won't appear here.
959
960You probably don't need to use this - it mainly exists as a mechanism to recreate the previous (now-changed) behavior of `pendingMocks()`.
961
962```js
963console.error('active mocks: %j', scope.activeMocks());
964```
965
966It is also available in the global scope:
967
968```js
969console.error('active mocks: %j', nock.activeMocks());
970```
971
972### .isActive()
973
974Your tests may sometimes want to deactivate the nock interceptor.
975Once deactivated, nock needs to be re-activated to work.
976You can check if nock interceptor is active or not by using `nock.isActive()`.
977Sample:
978
979```js
980if (!nock.isActive()) nock.activate()
981```
982
983## Logging
984
985Nock can log matches if you pass in a log function like this:
986
987```js
988var google = nock('http://google.com')
989 .log(console.log)
990 ...
991```
992
993## Restoring
994
995You can restore the HTTP interceptor to the normal unmocked behaviour by calling:
996
997```js
998nock.restore();
999```
1000**note 1**: restore does not clear the interceptor list. Use [nock.cleanAll()](#cleanall) if you expect the interceptor list to be empty.
1001
1002**note 2**: restore will also remove the http interceptor itself. You need to run [nock.activate()](#activating) to re-activate the http interceptor. Without re-activation, nock will not intercept any calls.
1003
1004## Activating
1005
1006Only for cases where nock has been deactivated using [nock.restore()](#restoring), you can reactivate the HTTP interceptor to start intercepting HTTP calls using:
1007
1008```js
1009nock.activate();
1010```
1011
1012**note**: To check if nock HTTP interceptor is active or deactive, use [nock.isActive()](#isactive).
1013
1014## Turning Nock Off (experimental!)
1015
1016You can bypass Nock completely by setting `NOCK_OFF` environment variable to `"true"`.
1017
1018This way you can have your tests hit the real servers just by switching on this environment variable.
1019
1020```js
1021$ NOCK_OFF=true node my_test.js
1022```
1023
1024## Enable/Disable real HTTP request
1025
1026By default, any requests made to a host that is not mocked will be executed normally. If you want to block these requests, nock allows you to do so.
1027
1028For disabling real http requests.
1029
1030```js
1031nock.disableNetConnect();
1032```
1033
1034So, if you try to request any host not 'nocked', it will thrown an `NetConnectNotAllowedError`.
1035
1036```js
1037nock.disableNetConnect();
1038var req = http.get('http://google.com/');
1039req.on('error', function(err){
1040 console.log(err);
1041});
1042// The returned `http.ClientRequest` will emit an error event (or throw if you're not listening for it)
1043// This code will log a NetConnectNotAllowedError with message:
1044// Nock: Not allow net connect for "google.com:80"
1045```
1046
1047For enabling real HTTP requests (the default behaviour).
1048
1049```js
1050nock.enableNetConnect();
1051```
1052
1053You could allow real HTTP request for certain host names by providing a string or a regular expression for the hostname:
1054
1055```js
1056// using a string
1057nock.enableNetConnect('amazon.com');
1058
1059// or a RegExp
1060nock.enableNetConnect(/(amazon|github).com/);
1061
1062http.get('http://www.amazon.com/');
1063http.get('http://github.com/'); // only for second example
1064
1065// This request will be done!
1066http.get('http://google.com/');
1067// this will throw NetConnectNotAllowedError with message:
1068// Nock: Not allow net connect for "google.com:80"
1069```
1070
1071A common use case when testing local endpoints would be to disable all but local host, then adding in additional nocks for external requests:
1072
1073```js
1074nock.disableNetConnect();
1075nock.enableNetConnect('127.0.0.1'); //Allow localhost connections so we can test local routes and mock servers.
1076```
1077Then when you're done with the test, you probably want to set everything back to normal:
1078
1079```js
1080nock.cleanAll();
1081nock.enableNetConnect();
1082```
1083
1084## Recording
1085
1086This is a cool feature:
1087
1088Guessing what the HTTP calls are is a mess, especially if you are introducing nock on your already-coded tests.
1089
1090For these cases where you want to mock an existing live system you can record and playback the HTTP calls like this:
1091
1092```js
1093nock.recorder.rec();
1094// Some HTTP calls happen and the nock code necessary to mock
1095// those calls will be outputted to console
1096```
1097
1098Recording relies on intercepting real requests and answers and then persisting them for later use.
1099
1100In order to stop recording you should call `nock.restore()` and recording will stop.
1101
1102**ATTENTION!:** when recording is enabled, nock does no validation, nor will any mocks be enabled. Please be sure to turn off recording before attempting to use any mocks in your tests.
1103
1104### `dont_print` option
1105
1106If you just want to capture the generated code into a var as an array you can use:
1107
1108```js
1109nock.recorder.rec({
1110 dont_print: true
1111});
1112// ... some HTTP calls
1113var nockCalls = nock.recorder.play();
1114```
1115
1116The `nockCalls` var will contain an array of strings representing the generated code you need.
1117
1118Copy and paste that code into your tests, customize at will, and you're done! You can call `nock.recorder.reset()` to remove already recorded calls from the array that `nock.recorder.play()` returns.
1119
1120(Remember that you should do this one test at a time).
1121
1122### `output_objects` option
1123
1124In case you want to generate the code yourself or use the test data in some other way, you can pass the `output_objects` option to `rec`:
1125
1126```js
1127nock.recorder.rec({
1128 output_objects: true
1129});
1130// ... some HTTP calls
1131var nockCallObjects = nock.recorder.play();
1132```
1133
1134The returned call objects have the following properties:
1135
1136* `scope` - the scope of the call including the protocol and non-standard ports (e.g. `'https://github.com:12345'`)
1137* `method` - the HTTP verb of the call (e.g. `'GET'`)
1138* `path` - the path of the call (e.g. `'/pgte/nock'`)
1139* `body` - the body of the call, if any
1140* `status` - the HTTP status of the reply (e.g. `200`)
1141* `response` - the body of the reply which can be a JSON, string, hex string representing binary buffers or an array of such hex strings (when handling `content-encoded` in reply header)
1142* `headers` - the headers of the reply
1143* `reqheader` - the headers of the request
1144
1145If you save this as a JSON file, you can load them directly through `nock.load(path)`. Then you can post-process them before using them in the tests for example to add them request body filtering (shown here fixing timestamps to match the ones captured during recording):
1146
1147```js
1148nocks = nock.load(pathToJson);
1149nocks.forEach(function(nock) {
1150 nock.filteringRequestBody = function(body, aRecordedBody) {
1151 if (typeof(body) !== 'string' || typeof(aRecordedBody) !== 'string') {
1152 return body;
1153 }
1154
1155 var recordedBodyResult = /timestamp:([0-9]+)/.exec(aRecordedBody);
1156 if (!recordedBodyResult) {
1157 return body;
1158 }
1159
1160 var recordedTimestamp = recordedBodyResult[1];
1161 return body.replace(/(timestamp):([0-9]+)/g, function(match, key, value) {
1162 return key + ':' + recordedTimestamp;
1163 });
1164 };
1165});
1166```
1167
1168Alternatively, if you need to pre-process the captured nock definitions before using them (e.g. to add scope filtering) then you can use `nock.loadDefs(path)` and `nock.define(nockDefs)`. Shown here is scope filtering for Dropbox node module which constantly changes the subdomain to which it sends the requests:
1169
1170```js
1171// Pre-process the nock definitions as scope filtering has to be defined before the nocks are defined (due to its very hacky nature).
1172var nockDefs = nock.loadDefs(pathToJson);
1173nockDefs.forEach(function(def) {
1174 // Do something with the definition object e.g. scope filtering.
1175 def.options = def.options || {};
1176 def.options.filteringScope = function(scope) {
1177 return /^https:\/\/api[0-9]*.dropbox.com/.test(scope);
1178 };
1179}
1180
1181// Load the nocks from pre-processed definitions.
1182var nocks = nock.define(nockDefs);
1183```
1184
1185### `enable_reqheaders_recording` option
1186
1187Recording request headers by default is deemed more trouble than its worth as some of them depend on the timestamp or other values that may change after the tests have been recorder thus leading to complex postprocessing of recorded tests. Thus by default the request headers are not recorded.
1188
1189The genuine use cases for recording request headers (e.g. checking authorization) can be handled manually or by using `enable_reqheaders_recording` in `recorder.rec()` options.
1190
1191```js
1192nock.recorder.rec({
1193 dont_print: true,
1194 output_objects: true,
1195 enable_reqheaders_recording: true
1196});
1197```
1198
1199Note that even when request headers recording is enabled Nock will never record `user-agent` headers. `user-agent` values change with the version of Node and underlying operating system and are thus useless for matching as all that they can indicate is that the user agent isn't the one that was used to record the tests.
1200
1201### `logging` option
1202
1203Nock will print using `console.log` by default (assuming that `dont_print` is `false`). If a different function is passed into `logging`, nock will send the log string (or object, when using `output_objects`) to that function. Here's a basic example.
1204
1205```js
1206var appendLogToFile = function(content) {
1207 fs.appendFile('record.txt', content);
1208}
1209nock.recorder.rec({
1210 logging: appendLogToFile,
1211});
1212```
1213
1214### `use_separator` option
1215
1216By default, nock will wrap it's output with the separator string `<<<<<<-- cut here -->>>>>>` before and after anything it prints, whether to the console or a custom log function given with the `logging` option.
1217
1218To disable this, set `use_separator` to false.
1219
1220```js
1221nock.recorder.rec({
1222 use_separator: false
1223});
1224```
1225
1226### .removeInterceptor()
1227This allows removing a specific interceptor. This can be either an interceptor instance or options for a url. It's useful when there's a list of common interceptors shared between tests, where an individual test requires one of the shared interceptors to behave differently.
1228
1229Examples:
1230```js
1231nock.removeInterceptor({
1232 hostname : 'localhost',
1233 path : '/mockedResource'
1234});
1235```
1236
1237```js
1238nock.removeInterceptor({
1239 hostname : 'localhost',
1240 path : '/login'
1241 method: 'POST'
1242 proto : 'https'
1243});
1244```
1245
1246```js
1247var interceptor = nock('http://example.org')
1248 .get('somePath');
1249nock.removeInterceptor(interceptor);
1250```
1251
1252## Events
1253
1254A scope emits the following events:
1255
1256* `emit('request', function(req, interceptor, body))`;
1257* `emit('replied', function(req, interceptor))`;
1258
1259### Global no match event
1260
1261You can also listen for no match events like this:
1262
1263```js
1264nock.emitter.on('no match', function(req) {
1265
1266});
1267```
1268
1269## Nock Back
1270
1271fixture recording support and playback
1272
1273### Setup
1274
1275**You must specify a fixture directory before using, for example:
1276
1277In your test helper
1278
1279```javascript
1280var nockBack = require('nock').back;
1281
1282nockBack.fixtures = '/path/to/fixtures/';
1283nockBack.setMode('record');
1284```
1285
1286#### Options
1287
1288- `nockBack.fixtures` : path to fixture directory
1289- `nockBack.setMode()` : the mode to use
1290
1291
1292### Usage
1293
1294By default if the fixture doesn't exist, a `nockBack` will create a new fixture and save the recorded output
1295for you. The next time you run the test, if the fixture exists, it will be loaded in.
1296
1297The `this` context of the callback function will have a property `scopes` to access all of the loaded
1298nock scopes.
1299
1300```javascript
1301var nockBack = require('nock').back;
1302var request = require('request');
1303nockBack.setMode('record');
1304
1305nockBack.fixtures = __dirname + '/nockFixtures'; //this only needs to be set once in your test helper
1306
1307var before = function(scope) {
1308 scope.filteringRequestBody = function(body, aRecordedBody) {
1309 if (typeof(body) !== 'string' || typeof(aRecordedBody) !== 'string') {
1310 return body;
1311 }
1312
1313 var recordedBodyResult = /timestamp:([0-9]+)/.exec(aRecordedBody);
1314 if (!recordedBodyResult) {
1315 return body;
1316 }
1317
1318 var recordedTimestamp = recordedBodyResult[1];
1319 return body.replace(/(timestamp):([0-9]+)/g, function(match, key, value) {
1320 return key + ':' + recordedTimestamp;
1321 });
1322 };
1323}
1324
1325// recording of the fixture
1326nockBack('zomboFixture.json', function(nockDone) {
1327 request.get('http://zombo.com', function(err, res, body) {
1328 nockDone();
1329
1330
1331 // usage of the created fixture
1332 nockBack('zomboFixture.json', function (nockDone) {
1333 http.get('http://zombo.com/').end(); // respond body "Ok"
1334
1335 this.assertScopesFinished(); //throws an exception if all nocks in fixture were not satisfied
1336 http.get('http://zombo.com/').end(); // throws exception because someFixture.json only had one call
1337
1338 nockDone(); //never gets here
1339 });
1340 });
1341});
1342```
1343
1344If your tests are using promises then use `nockBack` like this:
1345
1346```
1347return nockBack('promisedFixture.json')
1348 .then(({nockDone, context}) => {
1349 // do your tests returning a promise and chain it with
1350 // `.then(nockDone);`
1351 });
1352});
1353```
1354
1355#### Options
1356
1357As an optional second parameter you can pass the following options
1358
1359- `before`: a preprocessing function, gets called before nock.define
1360- `after`: a postprocessing function, gets called after nock.define
1361- `afterRecord`: a postprocessing function, gets called after recording. Is passed the array of scopes recorded and should return the array scopes to save to the fixture
1362- `recorder`: custom options to pass to the recorder
1363
1364
1365#### Modes
1366
1367to set the mode call `nockBack.setMode(mode)` or run the tests with the `NOCK_BACK_MODE` environment variable set before loading nock. If the mode needs to be changed programatically, the following is valid: `nockBack.setMode(nockBack.currentMode)`
1368
1369- wild: all requests go out to the internet, don't replay anything, doesn't record anything
1370
1371- dryrun: The default, use recorded nocks, allow http calls, doesn't record anything, useful for writing new tests
1372
1373- record: use recorded nocks, record new nocks
1374
1375- lockdown: use recorded nocks, disables all http calls even when not nocked, doesn't record
1376
1377## Debugging
1378Nock uses debug, so just run with environmental variable DEBUG set to nock.*
1379
1380```js
1381$ DEBUG=nock.* node my_test.js
1382```
1383
1384## PROTIP
1385
1386If you don't want to match the request body you can use this trick (by @theycallmeswift):
1387
1388```js
1389var scope = nock('http://api.myservice.com')
1390 .filteringRequestBody(function(body) {
1391 return '*';
1392 })
1393 .post('/some_uri', '*')
1394 .reply(200, 'OK');
1395```
1396
1397## Contributing
1398
1399Thanks for wanting to contribute! Take a look at our [Contributing Guide](CONTRIBUTING.md) for notes on our commit message conventions and how to run tests.
1400
1401Please note that this project is released with a [Contributor Code of Conduct](./CODE_OF_CONDUCT.md).
1402By participating in this project you agree to abide by its terms.
1403
1404## License
1405
1406[MIT](LICENSE)
1407
1408Copyright (c) 2011-2017 [Pedro Teixeira](http://about.me/pedroteixeira) and other [contributors](https://github.com/nock/nock/graphs/contributors).