Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test error in request with Nock?

Tags:

I want to test the error in a request return. I'm using nock in my tests, how can I force Nock to provoke an error? I want to achieve 100% test coverage and need to test err branch for that

request('/foo', function(err, res) {   if(err) console.log('boom!'); }); 

Never enter in the if err branch. Even if hit err is a valid response, my Nock line in test looks like this

nock('http://localhost:3000').get('/foo').reply(400); 

edit: thanks to some comments:

  • I'm trying to mock an error in the request. From node manual: https://nodejs.org/api/http.html#http_http_request_options_callback If any error is encountered during the request (be that with DNS resolution, TCP level errors, or actual HTTP parse errors) an 'error' event is emitted on the returned request object
  • An error code (e.g. 4xx) doesn't define the err variable. I'm trying to mock exactly that, whatever error that defines the err variable and evaluates to true
like image 710
coolxeo Avatar asked Dec 30 '14 16:12

coolxeo


People also ask

What is Nock testing?

Nock is an HTTP server mocking and expectations library. You can use this library to test frontend modules that are performing HTTP requests. You can test in isolation because Nock lets you dictate what our API responses will be.

What is Nock API?

Nock is an HTTP server mocking and expectations library. Nock works by overriding Node's http. request function. It helps us mock calls to API and specifies what URLs we want to listen for, and responds with predefined responses, just like real APIs would.

What is Nock node?

Nock is an HTTP server mocking and expectations library for Node. js. Nock works by overriding the http. request and http. ClientRequest functions, intercepting all requests made to a specified URL and returning specified responses that mimic the data that the real URL would return.


2 Answers

Use replyWithError. From the docs:

    nock('http://www.google.com')    .get('/cat-poems')    .replyWithError('something awful happened'); 
like image 75
Krzysiek Szlapinski Avatar answered Oct 06 '22 21:10

Krzysiek Szlapinski


When you initialise a http(s) request with request(url, callback), it returns an event emitter instance (along with some custom properties/methods).

As long as you can get your hands on this object (this might require some refactoring or perhaps it might not even be suitable for you) you can make this emitter to emit an error event, thus firing your callback with err being the error you emitted.

The following code snippet demonstrates this.

'use strict';  // Just importing the module var request = require('request') // google is now an event emitter that we can emit from!   , google = request('http://google.com', function (err, res) {       console.log(err) // Guess what this will be...?     })  // In the next tick, make the emitter emit an error event // which will trigger the above callback with err being // our Error object. process.nextTick(function () {   google.emit('error', new Error('test')) }) 

EDIT

The problem with this approach is that it, in most situations, requires a bit of refactoring. An alternative approach exploits the fact that Node's native modules are cached and reused across the whole application, thus we can modify the http module and Request will see our modifications. The trick is in monkey-patching the http.request() method and injecting our own bit of logic into it.

The following code snippet demonstrates this.

'use strict';  // Just importing the module var request = require('request')   , http = require('http')   , httpRequest = http.request  // Monkey-patch the http.request method with // our implementation http.request = function (opts, cb) {   console.log('ping');   // Call the original implementation of http.request()   var req = httpRequest(opts, cb)    // In next tick, simulate an error in the http module   process.nextTick(function () {     req.emit('error', new Error('you shall not pass!'))     // Prevent Request from waiting for     // this request to finish     req.removeAllListeners('response')     // Properly close the current request     req.end()   })    // We must return this value to keep it   // consistent with original implementation   return req }  request('http://google.com', function (err) {   console.log(err) // Guess what this will be...? }) 

I suspect that Nock does something similar (replacing methods on the http module) so I recommend that you apply this monkey-patch after you have required (and perhaps also configured?) Nock.

Note that it will be your task to make sure you emit the error only when the correct URL is requested (inspecting the opts object) and to restore the original http.request() implementation so that future tests are not affected by your changes.

like image 33
Robert Rossmann Avatar answered Oct 06 '22 20:10

Robert Rossmann