It generally goes without saying these days that testing is an important part of the development process. However, testing is not always the easiest thing to master, and it can be difficult to know where to start, especially when it comes to learning a new language. [Node.js]( adds an extra twist on this difficulty, in that your code is running Asynchronously, and you will often be dealing with HTTP calls. Having just been through the process of learning Node.js and working on a simple application that deals with calling and receiving responses from an external API, the most painful thing I found was that there aren't many tutorials on how to test HTTP requests and responses that I find particularly clear. So, this tutorial aims to provide clear information on how to effectively test your requests and responses, with a little bit about testing emitted events. ## Setting up the Test Environment For these tests we'll be using the [Mocha]( testing framework along with the [Chai]( assertion library. We'll also use the popular [Request]( library to send requests to our server. Create a new folder for you project and install Mocha, Chai, and Request to it by running: npm install mocha chai request By default, Mocha looks for tests in a folder called ```/test``` within the project root, so create the folder with: mkdir test In order to run our tests we'll set up a [Makefile]( in the project root, the code of which looks like this: REPORTER = spec test: @NODE_ENV=test ./node_modules/.bin/mocha \ --reporter $(REPORTER) \ --ui tdd test-w: @NODE_ENV=test ./node_modules/.bin/mocha \ --reporter $(REPORTER) \ --growl \ --ui tdd \ --watch .PHONY: test test-w Be careful when you're creating the Makefile that you indent the lines with _Tab_ characters and not spaces. You can now run your tests once with: make test You should see something like ```0 passing (2ms)```, which indicates that the test suite ran but didn't find any tests. If you see an error then the most likely options are probably that you've got spaces in your Makefile, or that Make can't find Mocha, in which case check that you have a ```/node_modules``` directory in your project folder and that Mocha is installed to it. Alternatively, you can also run the tests continuously in the background with: make test-w The _make test_ command should also be added to the _scripts_ section of your _package.json_ file, and Mocha, Chai, and Request to _devdependencies_; like so: // ./package.json { "scripts": { "test": "make test" }, "devDependencies": { "mocha": "*", "chai": "*", "request": "*" } } ## Creating our Server Next we'll create the server that we'll be testing (Yes, by most standards writing the code before the tests is backasswards, but this is for demo purposes). This server will listen for requests and respond according to the content of the request header. If the request has a [Content-Type]( header of 'text/plain' it will respond with an HTTP 200 "OK" code and emit an [Event]( called _success_ containing the body of the request. For any other Content-Type header we will return an HTTP 400 "Bad Request" error. Create a ```server.js``` file in a new ```lib``` folder in your project directory, with the code below: // ./lib/server.js var http = require('http'); var server = module.exports = http.createServer(function (req, res) { if (req.headers['content-type'] === 'text/plain') { var body = ''; req.on('data', function (chunk) { body += chunk.toString(); }); req.on('end', function () { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('correct header'); server.emit('success', body); }); } else { res.writeHead(400, {'Content-Type': 'text/plain'}); res.end('wrong header'); }; }); ## Setting up the Tests Before we write our first test, we need to do a little more setup. The first thing we will need to do is to require Chai's _expect_ function in our test suite. So we'll create a file in our _/test_ folder called tests.js: touch test/tests.js And with the first two lines we'll require the expect function from Chai: var expect = require('Chai').expect; You may have noticed that our server doesn't start automatically, as it has no _listen_ call. The second line of our server code contains a [module export]( that allows our server to be imported into another file. We can then start the server before our tests run, and close it when they finish. To do this we need to import our server into 'tests.js', and within the main 'describe' function in which we write our tests we'll include 'before' and 'after' functions. // ./test/tests.js var server = require('../lib/server.js'); describe('server response', function () { before(function () { server.listen(8000); }); after(function () { server.close(); }); }); ## Writing the Response Tests We can now get round to actually writing our tests. We'll write three tests, in order to test each response from our server; the incorrect header response, the successful header response, and the data emitted on a successful response. First, we need to require the Request library at the beginning of _test.js_: var request = require('request'); Now we can include the test within our 'describe' function, immediately below the 'after' function: it('should return 400', function (done) { request.get('http://localhost:8000', function (err, res, body){ expect(res.statusCode).to.equal(400); expect(res.body).to.equal('wrong header'); done(); }); }); The _it_ statement, just like _describe_, _before_, and _after_, follows the [BDD]( standard for writing tests. We begin by describing what the test should return, and then a function containing the tests. Because our code is Asynchronous, we need to invoke a callback (in this case called _done_) so that Mocha knows to wait until the test is complete. The second line begins our request to the server. We're calling request with a _GET_ (though it could just as well be _POST_) and passing in the address of our server; in this case localhost listening on port 8000. There is also a function with _error_, _response_, and _body_ callbacks. Within the function we're listening for a response, and this is where the test really happens. The Chai assertion library works by chaining together natural language assertions, making the tests fairly easy to read. In this case we're expecting the StatusCode of the response to equal _400_ and the body of the response to read _wrong header_. The final part of the code is the _done()_ callback; without which the test will exit with a timeout error. Our second test will test the response if the request contains the _Content-Type: text/plain_ header. it('should return 200', function (done) { var options = { url: 'http://localhost:8000', headers: { 'Content-Type': 'text/plain' } }; request.get(options, function (err, res, body) { expect(res.statusCode).to.equal(200); expect(res.body).to.equal('correct header'); done(); }); }); This test is much like the first, expect we've added an options object containing the destination url and headers of our request. This is passed as the first parameter of the request, so that our request will be sent to http://localhost:8000 with the correct _Content-Type_ header. By creating an options object like this it become very easy to use the Request library to create a request with any parameters we'd like. These two tests show the basic form for creating thorough HTTP Server tests. By adding more expect statements and adding different [parameters]( to the chain, you can easily test all the different parts of your responses. ## Testing Emitters Now that we can test our responses, I figure that the next step might be to test what our code is emitting internally. While not technically part of the scope of this article, if you're developing and testing HTTP Requests and Responses in Node.js, at some point your going to be using event emitters and listeners, and in fact you already have. In our server the code ```req.on('data', function () {});``` is an event listener, listening for the _data_ event that is emitted when we receive data. Same with the ```req.on('end')``` function. As you can see if you look back at our server code, once we receive the _end_ event, we send out our own _success_ event that contains the body of the received request. To test that we're successfully emitting, we'll add a body to our request, and we'll need to set a timeout in our test to make sure that the event is firing within a reasonable time. it('should emit request body', function (done) { var options = { url: 'http://localhost:8000', headers: { 'Content-Type': 'text/plain' }, body: 'successfully emitted request' }; var eventFired = false; request.get(options, function (err, res, body) {}); server.on('success', function (data) { eventFired = true; expect(data).to.equal('successfully emitted request'); }); setTimeout( function () { expect(eventFired).to.equal(true); done(); }, 10); }); We have now attached a body to our request, that should be emitted back to us, and an _eventFired_ variable set to _false_, that will be set to true when the event fires. The expect statements are no longer in the _request_ function, as we are not testing the HTTP response. The code ```server.on('success', function (data) {})``` listens for the success event, and passes the data from that event into a function. Within the function we set _eventFired_ to true, and test to see that the emitted data is correct. The _setTimeout_ function is required in order to properly test that the event fired. If the event does not fire, then the test will fail gracefully rather than with a timeout error. ## Conclusion We now have some basic tests that should reasonably cover the server code. This basic setup should work with most Node.js projects, and the general idea of this sort of testing is an essential skill in any programming language. If you'd like to have a look at or download and test the full code yourself then it can be found [here](