Testing Hubot Scripts

05:54 reading time

TL;DR Hubot Test Helper works great with the most recent versions of Hubot and Node. With older versions, YMMV. You can find sample tests here and here. They use some convenience methods found here.

Recently our team decided to upgrade to the latest version of Hubot. We’re running version 2.10.0, pretty far behind the current version (2.16.0). We had attempted to upgrade previously, but we discovered that later versions of Hubot broke our test suite. It’s time to find a new way to test!

Let’s start with some research. I found an issue on GitHub called “Define and document testing patterns for scripts”. There are pointers to two testing options: Hubot Mock Adapter and Hubot Test Helper. To me, Hubot Mock Adapter looks like a dead end. It hasn’t been updated for well over a year, and based on a comment from willdurand it won’t work with Hubot 2.14+. So that leaves Hubot Test Helper. Let’s try it out.

[I’ve set up a GitHub repository with all the steps described in this article. Throughout this post I’ll link to the relevant commits, and you can see the whole repository here.]

First I’ll create a new Hubot instance using Node 4.1.1. Next I’ll install the Hubot Test Helper [acebfc]:

npm install hubot-test-helper --save-dev

Now I want to replicate the sample test in the Hubot Test Helper README. It’s a mocha script that also depends on co and chai. The use of co is interesting.
Hubot Test Helper uses promises to enable its aynchronous testing. I only use Node for Hubot, so I haven’t run into promises until now. It looks like co will return a Promise, and Mocha has built-in support for resolving Promises returned from a beforeEach method.

If I’m going to write my tests in CoffeeScript, I’ll need to install it as well. Let’s get all these dependencies ready [acebfc…2e4e7d]:

npm install mocha --save-dev
npm install co --save-dev
npm install chai --save-dev
npm install coffee-script --save-dev

Now I’ll add the tests [4f86b8] to my Hubot instance and run them.

$ mocha --compilers "coffee:coffee-script/register" tests/test_hi.coffee

    user says hi to hubot
      ✓ should reply to user

  1 passing (152ms)

Good news! The test is running great with the latest versions of Hubot. While I should be able to get all my tests running now, I do have some concerns with the syntax in the sample test. My main complaint is that the test uses a beforeEach method to run the Hubot commands. That may make sense for multiple Hubot commands, but it’s pretty verbose for single commands.

context 'user says hi to hubot', ->
  beforeEach ->
    co =>
      yield @room.user.say 'alice', '@hubot hi'

  it 'should reply to user', ->
    expect(@room.messages).to.eql [
      ['alice', '@hubot hi']
      ['hubot', '@alice hi']

I have lots of tests to update, and I don’t want to create a separate Mocha context and beforeEach method for every one. Fortunately there is an alternative. For simpler tests, we can chain the assertion directly to the Hubot command instead [135a246]:

it 'should reply to user', ->
  @room.user.say('alice', '@hubot hi').then =>
    expect(@room.messages).to.eql [
      ['alice', '@hubot hi']
      ['hubot', '@alice hi']

This also removed the dependency on co. Yay! I don’t want to write @room.user.say(username, message) every time though, so let’s write a class to shorten that up a bit. We’ll do a little more cleanup too [36dbde9]. Now there is a simpler @utils.say(message) method with an optional user:

it 'should reply to user', ->
  @utils.say('@hubot hi', user: 'alice').then =>
    expect(@room.messages).to.eql [
      ['alice', '@hubot hi']
      ['hubot', '@alice hi']

Pretty good!

OK, let’s test something different. Here is a script that spits out random emoji (thanks to Jon Stern!). This script is sneaky, because Hubot “hears” the word emoji even if you’re not speaking to Hubot directly. Will the tests work in this case? Let’s find out! Fortunately Jon already wrote a test suite for this script, so I just need to update it to use the Hubot Test Helper syntax [3f947dd] and run the test:

$ mocha --compilers "coffee:coffee-script/register" tests/test_emoji.coffee

    random emoji
      ✓ should return an emoji
      ✓ should return 1 emoji
      ✓ should return 3 emoji
      ✓ literally returns zero emoji

  4 passing (184ms)

All right, let’s just add one more convenience method to make those responses [cbf2c09] a little easier to deal with. And we’re done.

In summary, Hubot Test Helper is a solid tool for testing Hubot!


Morgan Delagrange
Director, Software Engineering