Skip to main content

Unit testing in Keystone JS

·349 words·2 mins

After many annoying tests and messing about with Keystone.JS, I’ve finally managed to get a proper Unit Testing system in place.

What am I using?

We just need two super useful plugins to get started.

Mocha—our test framework will tell us what passes and fails Chai—our assertion library so we can run some tests How does it work?

In our package.json we’ve added a test script that sets up Mocha.

"scripts": {
    "start": "node keystone.js",
    "test": "./node_modules/.bin/mocha tests/init.js tests/unit/**"
}

This means that when we run (or in our case, CircleCI runs) npm test we’ll automatically launch into the Mocha test process and work through our assertions.

Our init.js script is simply used to setup the environment and get everything ready that we need to run tests.

process.env.NODE_ENV = process.env.NODE_ENV || 'test';
require('dotenv').load();

var keystone = require('keystone');
var chai = require('chai');

keystone.init({
  name: 'YourExactProjectName',
  's3 config': {}, //leave this here or stuff will break (magic)
});

keystone.import('../models');

chai.should();

Once we’ve done this, we can start adding tests to our /test/unit/ directory.

In the case of our project, I’m working with this folder structure:

/test/unit/
 — models
 — routes
 — views

The primary concern for the tests is the Model, and because we’re using Mongo, our tests will be running with a live connection to the database.

Here is an example of a test:

/*
  Post Unit Test
  for Keystone.JS built-in Post Model
 */
var keystone = require('keystone');
var chai = require('chai');
var dbURI = 'mongodb://localhost/<< YOUR DB >>' || process.env.MONGO_URL;
// CHANGE THIS AS NEEDED

describe('Posts', function () {
  beforeEach(function (done) {
    if (keystone.mongoose.connection.db) return done();
    console.log('Connecting to ' + dbURI);
    keystone.mongoose.connect(dbURI, done);
  });

  it('should be a connection to Mongo', function (done) {
    keystone.mongoose.connection.db.should.be.a('Object');
    done();
  });

  it('should be a Mongoose Model', function (done) {
    Post = keystone.list('Post');

    Post.should.be.a('Object');
    Post.should.have.property('model').be.a('Function');
    Post.should.have.property('schema').be.a('Object');

    done();
  });
});

Hopefully this will help you out with your own project. Feel free to comment if you have any difficulties and I’ll endeavour to respond with the answers!

P.S. Thanks to Prism.js for the syntax highlighting! I feel like it makes this all much easier to read.

Author
Will Hackett
I’m Will, a software engineer and architect based in Melbourne, Australia. I’m currently working at Blinq.