# TDD Hubot scripts with gulp+mocha

*2014-06-13*

> I configured mocha tests for my Hubot scripts.

I created [3 Hubot scripts] and published to [npm][npm], however I worried about that there are no unit tests with them.

So I configured them unit tests with [gulp] and [mocha].

<!--more-->

package.json
------------

I added the following npm packages to `devDependencies`:



Require modules for testing
---------------------------

I use:

- **[Chai Assertion Library]** to use `expect` matcher.
- **[nock]** to mock HTTP responses.

In the top of `yourscript_spec.coffee`:



The mock Hubot adapter
------------------

**[hubot-mock-adapter]** is a simple Hubot adapter that just emits events: `send`, `reply`, `topic`, `play` immediately.

Create [Robot] instance with `mock-adapter`.



This means:

- Loads adapter from npm modules.
- Uses [hubot-mock-adapter].
- HTTP server is on.
- Responds to messages with `TestHubot ...` prefix.

Load your script
----------------

To load scripts to test, call `Robot:loadFile`.

This method loads listeners and parses command helps written in comment.

Loading adapter should be connected to data source. So call them in `connected` event handler.



`hubot help` command is implemented in [help.coffee].


Test help commands
------------------

`Robot:loadFile` method loads scripts to parse command helps to list in help asynchronously.

So you need to wait for commands to be actually loaded before exit the scope.



then you can describe help response.



[Hubot v2.7.5] has a bug with help parser that adds prefix twice.

I fixed it and sent a [pull request#712] that was merged. (not yet published to npm.)

Catch exceptions in event handler
---------------------------------

On test failure in event handlers, `chai.AssertionError` might be thrown in event handlers and that kills process by default.

It needs to `try catch` and done with error if caught errors.



Mock HTTP
---------

I use [nock] that overrides native [http.ClientRequest] module to responses mock data.



[nock] also avoids all HTTP requests, call `nock.disableNetConnect()` on `beforeEach`.



For more details, read [nock documentation].

Clean stuff on afterEach
------------------------

### Close HTTP server

`Error: listen EADDRINUSE` will occur without closing [express] server.



### Clean HTTP mocking

If you test error handling, same error will occur other again without calling `nock.cleanAll()`.



gulpfile.coffee
---------------

From version 3.7.0, gulp supports gulpfiles written in CoffeeScript.

gulp watch exits on test failure
--------------------------------

[gulp-watch] exits on test failure by default.

To prevent this, emit `end` event in error handler like the below:



Make sure `mocha` pipe should pipe to `coffee` pipe.

[3 Hubot scripts]: https://github.com/search?q=user%3Angs+hubot&type=Repositories&ref=searchresults
[Hobot]: https://hubot.github.com
[npm]: http://npmjs.org
[gulp]: http://gulpjs.com/
[mocha]: http://visionmedia.github.io/mocha/
[hubot-mock-adapter]: https://github.com/blalor/hubot-mock-adapter
[Chai Assertion Library]: http://chaijs.com/
[nock]: https://github.com/pgte/nock
[nock documentation]: https://github.com/pgte/nock#readme
[Robot]: https://github.com/github/hubot/blob/master/src/robot.coffee
[http.ClientRequest]: http://nodejs.org/api/http.html#http_class_http_clientrequest
[gulp-watch]: https://github.com/floatdrop/gulp-watch
[gulp-mocha]: https://github.com/sindresorhus/gulp-mocha
[express]: http://expressjs.com/
[Hubot v2.7.5]: https://github.com/github/hubot/commit/04b97eada0018bfc049d88f47b91bce15e54f1bc
[pull request#712]: https://github.com/github/hubot/pull/712
[help.coffee]: https://github.com/github/hubot/blob/master/src/scripts/help.coffee


