bowling

Last time, I talked about the Bowling Game kata in Node.js, and mentioned that the next step in looking at the MEAN stack is Express, which is a JavaScript web application framework.

The inclusion of Express means that the game scoring will need to be exposed as a web application. This seems like a good use case for REST. I’m aware that restify is a better fit for this kind of application, but in keeping with exploration of the MEAN stack, I stuck with Express. In doing some more exploration with Restify, I found that it needs the node development environment to be installed on Windows, which I found off-putting.

For testing, I used supertest, which offers nice functionality for testing HTTP servers with a fluent interface, another programming technique that I’m fond of.

Here’s a sample of what the tests look like:

 var request = require('supertest'),
 should = require('should');
 var game = require('../game.js').app;

var assertScoreEquals = function(expectedScore) {
 request(game).get('/score').expect(200).end(function(err,res) {
 result = res.body;
 result.should.have.property('score').eql(expectedScore);
 });
 };

var roll = function(pins) {
 request(game).post('/bowl/' + pins).end();
 };

var rollMany = function(times, pins) {
 for (var i = 0; i < times; i++) {
 roll(pins);
 }
 };

describe('Scoring a bowling game', function() {
 beforeEach(function() {
 request(game).get('/start').end();
 });

describe('gutter game', function() {
 it('should return 0', function() {
 rollMany(20,0);
 assertScoreEquals(0);
 });
 });
 });
 

The supertest library is what provides the request object. Whenever you call request, you need to execute it with an end() call. I fumbled with this for a few hours. You’ll notice that I’m ignoring the error object. I found that when I tried to use it, not only did it clutter up the test code with a done callback:

 describe('gutter game', function() {
 it('should return 0', function(done) {
 rollMany(20,0);
 assertScoreEquals(0, done);
 });
 });
 

but I also found while running in a mocha -w loop, it caused Mocha to throw exceptions after some time elapsed. I need to dig into this deeper.

Here’s the game code, using Express to expose some REST endpoints for knocking down pins and scoring the game:

 var express = require('express');
 var app = exports.app = express();

app.get('/start', function(req,res) {
 rolls = new Array();
 ball = 0;
 });

app.post('/bowl/:pins', function(req,res) {
 rolls[ball] = parseInt(req.params.pins);
 ball++;
 });

app.get('/score', function(req,res) {
 var total = 0;
 var ball = 0;
 for(var frame = 0; frame < 10; frame++) {
 // omitted, the scoring algorithm
 }
 res.send(200, {score: total});
 });

app.listen(process.env.PORT || 3000);
 

As you can see, while the plumbing is more complicated, it uses the same structure as the pure Node.js solution. That’s why I find tools like the Bowling Game kata to be valuable. By solving a problem I’ve solved many times before, the problem fades into the background and I’m able to focus on learning the language.

The next step is to include AngularJS.